diff --git a/README.md b/README.md index a3740c3..65da4f5 100644 --- a/README.md +++ b/README.md @@ -241,16 +241,6 @@ stealth/ │ ├── components/ # FindingCard, VulnerabilityBadge │ ├── screens/ # InputScreen, LoadingScreen, ReportScreen │ └── services/ # walletService.js (API client) -├── backend/ -│ ├── script/ # Python scripts + regtest data -│ │ ├── setup.sh # Bootstrap bitcoind regtest -│ │ ├── reproduce.py # Create 12 vulnerability scenarios -│ │ ├── detect.py # Privacy vulnerability detector -│ │ ├── bitcoin_rpc.py # bitcoin-cli wrapper -│ │ ├── config.ini # Connection config (datadir, network) -│ │ └── bitcoin-data/ # Regtest chain data (gitignored) -│ └── src/StealthBackend/ # Quarkus Java REST API (single /api/wallet/scan endpoint) -├── slides/ # Slidev pitch presentation ├── api/ # stealth-api (Axum HTTP layer) │ ├── src/ │ └── tests/ diff --git a/backend/README.md b/backend/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/backend/requests/wallet.http b/backend/requests/wallet.http deleted file mode 100644 index 7926c9c..0000000 --- a/backend/requests/wallet.http +++ /dev/null @@ -1,53 +0,0 @@ -@baseUrl = http://localhost:8080 -@descriptor = wpkh([a1b2c3d4/84h/0h/0h]xpub6CatWdiZynkCminahu8Gmr7FAVnQXBTSMaBxn6qmBNkdm9tDkFzWmjmDrLBCQSTa7BHgpEjCXzMTCyDsQLSmcGYJHBB7cTwpqLNRKGP47uw/0/*)#qwer1234 - -### Analyze wallet -# @name analyze -POST {{baseUrl}}/api/wallet/analyze -Content-Type: application/json - -{ - "descriptor": "{{descriptor}}" -} - -> {% - client.test("status is 200", function() { - client.assert(response.status === 200, "expected 200"); - }); - client.test("response has analysisId", function() { - client.assert(typeof response.body.analysisId === "string", "expected analysisId string"); - client.assert(response.body.analysisId.length > 0, "expected non-empty analysisId"); - }); -%} - -### Get UTXOs -GET {{baseUrl}}/api/wallet/{{analyze.response.body.$.analysisId}}/utxos - -### Scan descriptor -# @name scan -GET {{baseUrl}}/api/wallet/scan?descriptor={{descriptor}} - -> {% - client.test("status is 200", function() { - client.assert(response.status === 200, "expected 200"); - }); - client.test("response has descriptor", function() { - client.assert(typeof response.body.descriptor === "string", "expected descriptor string"); - }); - client.test("summary totals are correct", function() { - client.assert(response.body.summary.total === 5, "expected 5 utxos"); - client.assert(response.body.summary.clean === 1, "expected 1 clean"); - client.assert(response.body.summary.vulnerable === 4, "expected 4 vulnerable"); - }); - client.test("utxos array has 5 items", function() { - client.assert(response.body.utxos.length === 5, "expected 5 utxos in array"); - }); - client.test("each utxo has required fields", function() { - response.body.utxos.forEach(function(utxo) { - client.assert(typeof utxo.txid === "string", "expected txid"); - client.assert(typeof utxo.address === "string", "expected address"); - client.assert(typeof utxo.amountBtc === "number", "expected amountBtc"); - client.assert(Array.isArray(utxo.vulnerabilities), "expected vulnerabilities array"); - }); - }); -%} diff --git a/backend/script/README.md b/backend/script/README.md deleted file mode 100644 index 7f3efbf..0000000 --- a/backend/script/README.md +++ /dev/null @@ -1,29 +0,0 @@ -pass: "aW2u~fYiuLu3)%a" - -METAMASK: -1.twenty -2.series -3.camera -4.invite -5.dismiss -6.gentle -7.dose -8.hotel -9.circle -10.eight -11.rotate -12.assault - -ENKRYPT: -damage -scare -aerobic -eagle -club -typical -cricket -kick -jaguar -paddle -void -dinner \ No newline at end of file diff --git a/backend/script/bitcoin_rpc.py b/backend/script/bitcoin_rpc.py deleted file mode 100644 index 0e06552..0000000 --- a/backend/script/bitcoin_rpc.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -bitcoin_rpc.py — Thin wrapper around bitcoin-cli for Python tests. -Connection settings are read from config.ini in the same directory. -""" - -import json -import subprocess -import os -import configparser - -# ── Load config ────────────────────────────────────────────────────────────── - -def _load_config(): - cfg = configparser.ConfigParser() - config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.ini") - cfg.read(config_path) - return cfg["bitcoin"] if "bitcoin" in cfg else {} - -def _build_base_args(section): - cli_bin = section.get("cli", "bitcoin-cli") - network = section.get("network", "regtest").strip().lower() - - args = [cli_bin] - - # Datadir — resolve relative paths from this file's directory - datadir = section.get("datadir", "").strip() - if datadir: - if not os.path.isabs(datadir): - datadir = os.path.join(os.path.dirname(os.path.abspath(__file__)), datadir) - args.append(f"-datadir={datadir}") - - network_flags = { - "regtest": "-regtest", - "testnet": "-testnet", - "signet": "-signet", - } - if network in network_flags: - args.append(network_flags[network]) - - for key, flag in [("rpchost", "-rpcconnect"), ("rpcport", "-rpcport"), - ("rpcuser", "-rpcuser"), ("rpcpassword", "-rpcpassword")]: - value = section.get(key, "").strip() - if value: - args.append(f"{flag}={value}") - - return args - -_cfg = _load_config() -_BASE_ARGS = _build_base_args(_cfg) - -def cli(*args, wallet=None): - """Call bitcoin-cli [network] [wallet] and return parsed JSON or string.""" - cmd = list(_BASE_ARGS) - if wallet: - cmd.append(f"-rpcwallet={wallet}") - cmd.extend(str(a) for a in args) - - result = subprocess.run(cmd, capture_output=True, text=True, timeout=60) - if result.returncode != 0: - raise RuntimeError(f"bitcoin-cli error: {result.stderr.strip()}\n cmd: {' '.join(cmd)}") - - output = result.stdout.strip() - if not output: - return None - try: - return json.loads(output) - except json.JSONDecodeError: - return output - - -def mine_blocks(n=1): - """Mine n blocks on regtest using generatetoaddress.""" - miner_addr = cli("getnewaddress", "", "bech32", wallet="miner") - cli("generatetoaddress", n, miner_addr) - return int(cli("getblockcount")) - - -def get_tx(txid): - """Get decoded transaction.""" - return cli("getrawtransaction", txid, "true") - - -def get_utxos(wallet_name, min_conf=0): - """List unspent outputs for a wallet.""" - return cli("listunspent", min_conf, wallet=wallet_name) - - -def get_balance(wallet_name): - """Get wallet balance.""" - return float(cli("getbalance", wallet=wallet_name)) - - -def send_raw(hex_tx): - """Broadcast a raw transaction.""" - return cli("sendrawtransaction", hex_tx) - - -def create_funded_psbt(wallet_name, inputs, outputs, options=None): - """Create a funded PSBT.""" - args = ["walletcreatefundedpsbt", json.dumps(inputs), json.dumps(outputs), 0] - if options: - args.append(json.dumps(options)) - return cli(*args, wallet=wallet_name) - - -def process_psbt(wallet_name, psbt): - """Sign a PSBT.""" - return cli("walletprocesspsbt", psbt, wallet=wallet_name) - - -def finalize_psbt(psbt): - """Finalize a PSBT.""" - return cli("finalizepsbt", psbt) - - -def create_raw_tx(inputs, outputs): - """Create a raw transaction.""" - return cli("createrawtransaction", json.dumps(inputs), json.dumps(outputs)) - - -def sign_raw_tx(wallet_name, hex_tx): - """Sign a raw transaction.""" - return cli("signrawtransactionwithwallet", hex_tx, wallet=wallet_name) - - -def get_block_count(): - """Get current block height.""" - return int(cli("getblockcount")) - - -def get_new_address(wallet_name, addr_type="bech32"): - """Get a new address.""" - return cli("getnewaddress", "", addr_type, wallet=wallet_name) - - -def send_to_address(wallet_name, address, amount): - """Send BTC to an address.""" - return cli("sendtoaddress", address, f"{amount:.8f}", wallet=wallet_name) - - diff --git a/backend/script/config.ini b/backend/script/config.ini deleted file mode 100644 index f863e5f..0000000 --- a/backend/script/config.ini +++ /dev/null @@ -1,17 +0,0 @@ -[bitcoin] -# Network to connect to: regtest | testnet | signet | mainnet -network = regtest - -# Path to the bitcoin-cli binary (use full path if not on PATH) -cli = bitcoin-cli - -# Data directory for bitcoind (matches setup.sh). -# Relative paths are resolved from the directory containing this file. -datadir = bitcoin-data - -# Optional: override RPC connection details. -# Leave these blank to use cookie auth from the datadir. -rpchost = -rpcport = -rpcuser = -rpcpassword = diff --git a/backend/script/detect.py b/backend/script/detect.py deleted file mode 100644 index 1a144f1..0000000 --- a/backend/script/detect.py +++ /dev/null @@ -1,1289 +0,0 @@ -#!/usr/bin/env python3 -""" -detect.py -========= -Blockchain privacy vulnerability detector. - -INPUT: One or more output descriptors (or --wallet to read them). -OUTPUT: Every privacy vulnerability found for that descriptor's address set. - -The detector creates a temporary watch-only wallet, imports descriptors with -a full rescan, then analyses all historical transactions touching any derived -address. It never scans the entire chain — only transactions the wallet knows. - -Usage: - python3 detect.py --wallet alice - python3 detect.py "wpkh([fp/84h/1h/0h]tpub.../0/*)#checksum" "wpkh([fp/84h/1h/0h]tpub.../1/*)#checksum" - python3 detect.py --wallet alice --known-risky-wallets risky --known-exchange-wallets exchange -""" - -import sys -import os -import json -import argparse -from collections import defaultdict - -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) -from bitcoin_rpc import cli, get_tx - -FINDINGS = [] -WARNINGS = [] - -def section(title): - print(f"[{title}]", file=sys.stderr) - -def finding(msg): - FINDINGS.append(msg) - -def warn(msg): - WARNINGS.append(msg) - -def ok(msg): - print(f"ok: {msg}", file=sys.stderr) - -def info(msg): - print(f" {msg}", file=sys.stderr) - - -# ═══════════════════════════════════════════════════════════════════════════════ -# 1. WALLET + ADDRESS RESOLUTION -# ═══════════════════════════════════════════════════════════════════════════════ - -def resolve_descriptors(args): - """Get the descriptor list from args: either --wallet or positional descriptors.""" - descs = [] - if args.wallet: - result = cli("listdescriptors", wallet=args.wallet) - for d in result["descriptors"]: - descs.append({ - "desc": d["desc"], - "internal": d.get("internal", False), - "active": d.get("active", True), - "range_end": d.get("range", [0, 999])[1] if isinstance(d.get("range"), list) else d.get("range", 999), - }) - else: - for raw in args.descriptors: - base = raw.split("#")[0] - if "/0/*" in base: - candidates = [(base, False), (base.replace("/0/*", "/1/*"), True)] - elif "/1/*" in base: - candidates = [(base.replace("/1/*", "/0/*"), False), (base, True)] - else: - candidates = [(base, False)] - for desc, internal in candidates: - try: - normalized = cli("getdescriptorinfo", desc)["descriptor"] - except Exception: - normalized = desc - descs.append({ - "desc": normalized, - "internal": internal, - "active": True, - "range_end": 999, - }) - return descs - - -def derive_all_addresses(descriptors): - """Derive addresses from all descriptors, return {address -> (desc_type, internal, index)}.""" - addr_map = {} # address -> metadata - for dinfo in descriptors: - desc = dinfo["desc"] - rng = min(dinfo["range_end"], 999) - # Detect descriptor type - dtype = "unknown" - if desc.startswith("wpkh("): dtype = "p2wpkh" - elif desc.startswith("tr("): dtype = "p2tr" - elif desc.startswith("sh(wpkh("): dtype = "p2sh-p2wpkh" - elif desc.startswith("pkh("): dtype = "p2pkh" - - try: - addrs = cli("deriveaddresses", desc, f"[0,{rng}]") - if addrs: - for i, a in enumerate(addrs): - addr_map[a] = { - "type": dtype, - "internal": dinfo["internal"], - "index": i, - } - except Exception as e: - info(f"Could not derive from {desc[:40]}…: {e}") - return addr_map - - -def build_scan_wallet(descriptors, wallet_name="_detect_scan"): - """Create a temporary watch-only wallet with descriptors, do full rescan.""" - # Clean up if exists - try: - cli("unloadwallet", wallet_name) - except Exception: - pass - - try: - cli("createwallet", wallet_name, "true", "true", "", "false", "true") - except Exception: - try: - cli("loadwallet", wallet_name) - except Exception: - pass - - import_batch = [] - for d in descriptors: - import_batch.append({ - "desc": d["desc"], - "timestamp": 0, # full rescan - "internal": d["internal"], - "active": d["active"], - "range": [0, d["range_end"]], - }) - - result = cli("importdescriptors", json.dumps(import_batch), wallet=wallet_name) - # Check results - for r in (result or []): - if not r.get("success"): - info(f"Import warning: {r.get('error', {}).get('message', 'unknown')}") - - return wallet_name - - -def get_all_transactions(wallet_name, count=10000): - """Get full transaction history for the wallet.""" - txs = cli("listtransactions", "*", count, 0, "true", wallet=wallet_name) - return txs or [] - - -def get_all_utxos(wallet_name): - """Get all UTXOs (confirmed and unconfirmed).""" - return cli("listunspent", 0, 9999999, wallet=wallet_name) or [] - - -# ═══════════════════════════════════════════════════════════════════════════════ -# 2. TRANSACTION GRAPH BUILDER -# ═══════════════════════════════════════════════════════════════════════════════ - -class TxGraph: - """Indexed view of all transactions touching our address set.""" - - def __init__(self, addr_map, wallet_txs, utxos): - self.addr_map = addr_map # {address -> metadata} - self.our_addrs = set(addr_map.keys()) - self.utxos = utxos # current UTXOs - self.tx_cache = {} # txid -> decoded tx - self._input_cache = {} # txid -> parsed input addresses - self._output_cache = {} # txid -> parsed output addresses - self.our_txids = set() # txids we participate in - - # Index: address -> list of (txid, direction, value) - self.addr_txs = defaultdict(list) # address -> [{txid, direction, amount}] - # Index: txid -> list of our addresses involved - self.tx_addrs = defaultdict(set) - - # Build from wallet tx list - for wtx in wallet_txs: - txid = wtx.get("txid", "") - addr = wtx.get("address", "") - cat = wtx.get("category", "") # send/receive - amount = wtx.get("amount", 0) - if txid: - self.our_txids.add(txid) - if addr and txid: - self.addr_txs[addr].append({ - "txid": txid, "category": cat, "amount": amount, - "confirmations": wtx.get("confirmations", 0), - "blockheight": wtx.get("blockheight", 0), - }) - self.tx_addrs[txid].add(addr) - - def fetch_tx(self, txid): - """Get decoded transaction (cached).""" - if txid not in self.tx_cache: - try: - self.tx_cache[txid] = get_tx(txid) - except Exception: - return None - return self.tx_cache[txid] - - def get_input_addresses(self, txid): - """Get all input addresses for a transaction (cached).""" - if txid in self._input_cache: - return self._input_cache[txid] - tx = self.fetch_tx(txid) - if not tx: - self._input_cache[txid] = [] - return [] - addrs = [] - for vin in tx.get("vin", []): - if vin.get("coinbase"): - continue - parent = self.fetch_tx(vin["txid"]) - if parent: - vout_data = parent["vout"][vin["vout"]] - addr = vout_data.get("scriptPubKey", {}).get("address", "") - value = vout_data.get("value", 0) - addrs.append({"address": addr, "value": value, "txid": vin["txid"], "vout": vin["vout"]}) - self._input_cache[txid] = addrs - return addrs - - def get_output_addresses(self, txid): - """Get all output addresses for a transaction (cached).""" - if txid in self._output_cache: - return self._output_cache[txid] - tx = self.fetch_tx(txid) - if not tx: - self._output_cache[txid] = [] - return [] - addrs = [] - for vout in tx.get("vout", []): - addr = vout.get("scriptPubKey", {}).get("address", "") - addrs.append({ - "address": addr, - "value": vout["value"], - "n": vout["n"], - "type": vout.get("scriptPubKey", {}).get("type", "unknown"), - }) - self._output_cache[txid] = addrs - return addrs - - def is_ours(self, address): - return address in self.our_addrs - - def get_script_type(self, address): - """Return the script type metadata for one of our addresses.""" - meta = self.addr_map.get(address) - if meta: - return meta["type"] - # Heuristic from prefix (supports mainnet, testnet/signet, regtest) - if address.startswith(("tb1q", "bc1q", "bcrt1q")): - return "p2wpkh" - if address.startswith(("tb1p", "bc1p", "bcrt1p")): - return "p2tr" - if address.startswith(("2", "3")): - return "p2sh-p2wpkh" - return "unknown" - - -# ═══════════════════════════════════════════════════════════════════════════════ -# 3. VULNERABILITY DETECTORS -# -# Each detector receives the TxGraph and reports findings. -# ═══════════════════════════════════════════════════════════════════════════════ - -def detect_01_address_reuse(g: TxGraph): - """Detect addresses that appear as recipients in multiple transactions.""" - section("1 · Address Reuse") - reused = {} - for addr in g.our_addrs: - # Count distinct TXIDs where this address received funds - receive_txids = set() - for entry in g.addr_txs.get(addr, []): - if entry["category"] == "receive": - receive_txids.add(entry["txid"]) - if len(receive_txids) >= 2: - reused[addr] = receive_txids - - if not reused: - ok("No address reuse detected.") - return - - for addr, txids in reused.items(): - meta = g.addr_map.get(addr, {}) - role = "change" if meta.get("internal") else "receive" - tx_list = [] - for txid in sorted(txids): - tx = g.fetch_tx(txid) - tx_list.append({"txid": txid, "confirmations": tx.get("confirmations", 0) if tx else 0}) - finding({ - "type": "ADDRESS_REUSE", - "severity": "HIGH", - "description": f"Address {addr} ({role}) reused across {len(txids)} transactions", - "details": { - "address": addr, - "role": role, - "tx_count": len(txids), - "txids": tx_list, - }, - "correction": ( - "Generate a fresh address for every payment received. " - "Enable HD wallet derivation (BIP-32/44/84) so your wallet produces a new address automatically. " - "If the address is a static donation or payment address, consider a Lightning invoice or a " - "payment-code scheme (BIP-47) that hides the on-chain address." - ), - }) - - -def detect_02_cioh(g: TxGraph): - """Detect multi-input transactions (CIOH) and verify input ownership.""" - section("2 · Common Input Ownership Heuristic (CIOH)") - found_any = False - - for txid in g.our_txids: - tx = g.fetch_tx(txid) - if not tx or len(tx.get("vin", [])) < 2: - continue - - input_addrs = g.get_input_addresses(txid) - if len(input_addrs) < 2: - continue - - # Classify inputs: ours vs external - our_inputs = [ia for ia in input_addrs if g.is_ours(ia["address"])] - ext_inputs = [ia for ia in input_addrs if not g.is_ours(ia["address"])] - total_inputs = len(input_addrs) - n_ours = len(our_inputs) - - if n_ours < 2: - # Only 1 of ours — CIOH doesn't expose us - continue - - found_any = True - n_outputs = len(tx.get("vout", [])) - ownership_pct = n_ours / total_inputs * 100 - - severity = "CRITICAL" if n_ours == total_inputs else "HIGH" - finding({ - "type": "CIOH", - "severity": severity, - "description": f"TX {txid} merges {n_ours}/{total_inputs} of your inputs ({round(ownership_pct)}% ownership)", - "details": { - "txid": txid, - "total_inputs": total_inputs, - "our_inputs": n_ours, - "external_inputs": len(ext_inputs), - "ownership_pct": round(ownership_pct), - "our_addresses": [ - { - "address": ia["address"], - "role": "change" if g.addr_map.get(ia["address"], {}).get("internal") else "receive", - "amount_btc": round(ia["value"], 8), - } - for ia in our_inputs - ], - }, - "correction": ( - "Use coin control to select only one UTXO per transaction when the payment amount allows it. " - "If consolidation is unavoidable, do it privately via a CoinJoin round so the link between " - "inputs is indistinguishable from other participants. " - "Alternatively, use the Lightning Network for small payments to avoid creating on-chain multi-input transactions." - ), - }) - - if not found_any: - ok("No multi-input transactions with ≥2 of your addresses detected.") - - -def detect_03_dust(g: TxGraph): - """Detect dust UTXOs (current and historical).""" - section("3 · Dust UTXO Detection") - DUST_SATS = 1000 - STRICT_DUST = 546 - - found = [] - for utxo in g.utxos: - sats = int(round(utxo["amount"] * 1e8)) - if sats <= DUST_SATS and g.is_ours(utxo.get("address", "")): - found.append(utxo) - - # Also check historical: any tx that sent dust to our addresses - hist_dust = [] - for txid in g.our_txids: - outputs = g.get_output_addresses(txid) - for out in outputs: - sats = int(round(out["value"] * 1e8)) - if sats <= DUST_SATS and g.is_ours(out["address"]): - hist_dust.append({"txid": txid, "address": out["address"], "sats": sats}) - - if not found and not hist_dust: - ok("No dust UTXOs detected.") - return - - if found: - for u in found: - sats = int(round(u["amount"] * 1e8)) - label = "STRICT_DUST" if sats <= STRICT_DUST else "dust-class" - finding({ - "type": "DUST", - "severity": "HIGH" if label == "STRICT_DUST" else "MEDIUM", - "description": f"Dust UTXO at {u['address']} ({sats} sats, {label}, unspent)", - "details": { - "status": "unspent", - "address": u["address"], - "sats": sats, - "label": label, - "txid": u["txid"], - "vout": u["vout"], - }, - "correction": ( - "Do not spend this dust output — doing so links your other inputs to this address via CIOH. " - "Use your wallet's coin freeze / UTXO management feature to exclude it from future transactions. " - "If the wallet does not support freezing, consider processing it through a CoinJoin round " - "so the tracking token is obfuscated before it touches any of your real UTXOs." - ), - }) - - # Deduplicate historical - seen = set() - unique_hist = [] - for h in hist_dust: - key = (h["txid"], h["address"]) - if key not in seen: - seen.add(key) - unique_hist.append(h) - - if unique_hist: - current_keys = {(u["txid"], u.get("address", "")) for u in found} - for h in unique_hist: - if (h["txid"], h["address"]) not in current_keys: - finding({ - "type": "DUST", - "severity": "LOW", - "description": f"Historical dust output at {h['address']} ({h['sats']} sats, already spent)", - "details": { - "status": "spent", - "address": h["address"], - "sats": h["sats"], - "txid": h["txid"], - }, - "correction": ( - "This dust has already been spent, so the tracking link is already on-chain. " - "Going forward, reject unsolicited dust by enabling automatic dust rejection in your wallet, " - "or use wallet software that warns before spending dust-class UTXOs." - ), - }) - - -def detect_04_dust_spending(g: TxGraph): - """Detect transactions that spend dust alongside normal inputs.""" - section("4 · Dust Spent with Normal Inputs") - DUST_SATS = 1000 - found_any = False - - for txid in g.our_txids: - input_addrs = g.get_input_addresses(txid) - if not input_addrs or len(input_addrs) < 2: - continue - - dust_inputs = [] - normal_inputs = [] - for ia in input_addrs: - if not g.is_ours(ia["address"]): - continue - sats = int(round(ia["value"] * 1e8)) - if sats <= DUST_SATS: - dust_inputs.append(ia) - elif sats > 10000: # > 10k sats = clearly normal - normal_inputs.append(ia) - - if dust_inputs and normal_inputs: - found_any = True - finding({ - "type": "DUST_SPENDING", - "severity": "HIGH", - "description": f"TX {txid} spends {len(dust_inputs)} dust input(s) alongside {len(normal_inputs)} normal input(s)", - "details": { - "txid": txid, - "dust_inputs": [{"address": d["address"], "sats": int(round(d["value"] * 1e8))} for d in dust_inputs], - "normal_inputs": [{"address": n["address"], "amount_btc": round(n["value"], 8)} for n in normal_inputs], - }, - "correction": ( - "Freeze dust UTXOs in your wallet to prevent them from being automatically selected as inputs. " - "Never manually include a dust UTXO in a transaction that also spends normal UTXOs, " - "as this permanently links those addresses. " - "If the dust must be reclaimed, do so in isolation via a dedicated CoinJoin or by sweeping only " - "the dust in a separate, low-value transaction with no other inputs." - ), - }) - - if not found_any: - ok("No dust spending mixed with normal inputs detected.") - - -def detect_05_change_detection(g: TxGraph): - """Detect transactions where change output is easily distinguishable.""" - section("5 · Probable Change Output Detection") - found_any = False - - for txid in g.our_txids: - tx = g.fetch_tx(txid) - if not tx: - continue - outputs = g.get_output_addresses(txid) - input_addrs = g.get_input_addresses(txid) - if not outputs or len(outputs) < 2: - continue - - # We only care about sends (where at least 1 input is ours) - our_in = [ia for ia in input_addrs if g.is_ours(ia["address"])] - if not our_in: - continue - - # Identify which outputs are ours (change) vs external (payment) - our_outs = [o for o in outputs if g.is_ours(o["address"])] - ext_outs = [o for o in outputs if not g.is_ours(o["address"])] - - if not our_outs or not ext_outs: - continue # can't distinguish change if all outputs are ours or all external - - # Check change-detection heuristics - problems = [] - - for change in our_outs: - ch_sats = int(round(change["value"] * 1e8)) - ch_round = ch_sats % 100000 == 0 or ch_sats % 1000000 == 0 - - for payment in ext_outs: - pay_sats = int(round(payment["value"] * 1e8)) - pay_round = pay_sats % 100000 == 0 or pay_sats % 1000000 == 0 - - # Heuristic 1: payment is round, change is not - if pay_round and not ch_round: - problems.append(f"Round payment ({pay_sats} sats) vs non-round change ({ch_sats} sats)") - - # Heuristic 2: change has same script type as input - in_types = set(g.get_script_type(ia["address"]) for ia in our_in) - ch_type = g.get_script_type(change["address"]) - if ch_type in in_types and change["type"] != payment["type"]: - problems.append( - f"Change script type ({change['type']}) matches input type — different from payment ({payment['type']})" - ) - - # Heuristic 3: change address is internal (derivation /1/*) - ch_meta = g.addr_map.get(change["address"], {}) - if ch_meta.get("internal"): - problems.append("Change uses an internal (BIP-44 /1/*) derivation path — standard wallet change pattern") - - if problems: - found_any = True - finding({ - "type": "CHANGE_DETECTION", - "severity": "MEDIUM", - "description": f"TX {txid} has identifiable change output(s) ({len(problems)} heuristic(s) matched)", - "details": { - "txid": txid, - "reasons": problems[:6], - "change_outputs": [{"address": co["address"], "amount_btc": round(co["value"], 8)} for co in our_outs], - }, - "correction": ( - "Use PayJoin (BIP-78) so the receiver also contributes an input, breaking the payment/change heuristic. " - "Alternatively, select a UTXO that exactly covers the payment amount (no change output needed). " - "Ensure your change address uses the same script type as the payment address. " - "Avoid sending round amounts so the change amount is not the obvious 'leftover'." - ), - }) - - if not found_any: - ok("No easily identifiable change outputs detected.") - - -def detect_06_consolidation_origin(g: TxGraph): - """Detect UTXOs that originate from a prior consolidation transaction.""" - section("6 · UTXOs from Prior Consolidation") - CONSOLIDATION_THRESHOLD = 3 # ≥3 inputs with ≤2 outputs = consolidation - found_any = False - - for utxo in g.utxos: - if not g.is_ours(utxo.get("address", "")): - continue - parent = g.fetch_tx(utxo["txid"]) - if not parent: - continue - n_in = len(parent.get("vin", [])) - n_out = len(parent.get("vout", [])) - if n_in >= CONSOLIDATION_THRESHOLD and n_out <= 2: - found_any = True - # Check how many of the consolidation inputs were ours - parent_inputs = g.get_input_addresses(utxo["txid"]) - our_parent_in = [ia for ia in parent_inputs if g.is_ours(ia["address"])] - finding({ - "type": "CONSOLIDATION", - "severity": "MEDIUM", - "description": f"UTXO {utxo['txid']}:{utxo['vout']} ({utxo['amount']:.8f} BTC) born from a {n_in}-input consolidation", - "details": { - "txid": utxo["txid"], - "vout": utxo["vout"], - "amount_btc": round(utxo["amount"], 8), - "consolidation_inputs": n_in, - "consolidation_outputs": n_out, - "our_inputs_in_consolidation": len(our_parent_in), - }, - "correction": ( - "Avoid consolidating many UTXOs into one in a single transaction, as it permanently links all " - "those addresses under CIOH. If fee savings require consolidation, do it during a period of low " - "fees and through a CoinJoin (e.g., Whirlpool or JoinMarket) so the link between inputs is " - "indistinguishable from other participants. " - "Consider keeping UTXOs separate and using coin selection strategies that minimize on-chain footprint." - ), - }) - - if not found_any: - ok("No UTXOs from prior consolidation detected.") - - -def detect_07_script_type_mixing(g: TxGraph): - """Detect transactions mixing different script types in inputs.""" - section("7 · Script Type Mixing in Inputs") - found_any = False - - for txid in g.our_txids: - input_addrs = g.get_input_addresses(txid) - if len(input_addrs) < 2: - continue - - our_in = [ia for ia in input_addrs if g.is_ours(ia["address"])] - if len(our_in) < 2: - continue - - types = set() - for ia in input_addrs: - types.add(g.get_script_type(ia["address"])) - - types.discard("unknown") - if len(types) >= 2: - found_any = True - finding({ - "type": "SCRIPT_TYPE_MIXING", - "severity": "HIGH", - "description": f"TX {txid} mixes input script types: {sorted(types)}", - "details": { - "txid": txid, - "script_types": sorted(types), - "inputs": [ - {"address": ia["address"], "script_type": g.get_script_type(ia["address"]), "ours": g.is_ours(ia["address"])} - for ia in input_addrs - ], - }, - "correction": ( - "Migrate all funds to a single address type — preferably Taproot (P2TR / bc1p) which offers the " - "largest anonymity set going forward. " - "Never mix P2PKH, P2SH-P2WPKH, P2WPKH, and P2TR inputs in the same transaction; each type " - "combination is a rare fingerprint. " - "Sweep legacy-type UTXOs to a fresh Taproot wallet through a CoinJoin to avoid the cross-type link." - ), - }) - - if not found_any: - ok("No script type mixing detected.") - - -def detect_08_cluster_merge(g: TxGraph): - """Detect transactions that merge UTXOs from different funding sources (clusters).""" - section("8 · Cluster Merge (Cross-Origin Input Mixing)") - found_any = False - - for txid in g.our_txids: - input_addrs = g.get_input_addresses(txid) - if len(input_addrs) < 2: - continue - - our_in = [ia for ia in input_addrs if g.is_ours(ia["address"])] - if len(our_in) < 2: - continue - - # Trace each of our inputs one hop back to find their funding sources - funding_sources = {} # our_input_txid:vout -> set of grandparent source txids - for ia in our_in: - parent_tx = g.fetch_tx(ia["txid"]) - if not parent_tx: - continue - gp_sources = set() - for p_vin in parent_tx.get("vin", []): - if p_vin.get("coinbase"): - gp_sources.add("coinbase") - else: - gp_sources.add(p_vin["txid"][:16]) - funding_sources[f"{ia['txid'][:16]}:{ia['vout']}"] = gp_sources - - # Check if funding sources differ - all_sources = list(funding_sources.values()) - if len(all_sources) >= 2: - # Are the source sets disjoint? (different clusters) - merged_clusters = False - for i in range(len(all_sources)): - for j in range(i + 1, len(all_sources)): - if all_sources[i].isdisjoint(all_sources[j]): - merged_clusters = True - - if merged_clusters: - found_any = True - finding({ - "type": "CLUSTER_MERGE", - "severity": "HIGH", - "description": f"TX {txid} merges UTXOs from {len(funding_sources)} different funding chains", - "details": { - "txid": txid, - "funding_sources": {k: sorted(v) for k, v in funding_sources.items()}, - }, - "correction": ( - "Use coin control to spend UTXOs from only one funding source per transaction. " - "Keep UTXOs received from different counterparties in separate wallets or accounts " - "so they are never accidentally merged. " - "If you must merge UTXOs from different origins, pass them through a CoinJoin first " - "to break the chain-analysis link before combining them." - ), - }) - - if not found_any: - ok("No cross-origin cluster merges detected.") - - -def detect_09_lookback_depth(g: TxGraph): - """Detect UTXOs with significantly different ages (dormancy patterns).""" - section("9 · UTXO Age / Lookback Depth") - - if not g.utxos: - ok("No UTXOs to analyze.") - return - - our_utxos = [u for u in g.utxos if g.is_ours(u.get("address", ""))] - if not our_utxos: - ok("No UTXOs belonging to the descriptor.") - return - - # Get confirmation counts - aged = [] - for u in our_utxos: - confs = u.get("confirmations", 0) - aged.append({"utxo": u, "confirmations": confs}) - - if len(aged) < 2: - ok("Only one UTXO, no age comparison possible.") - return - - aged.sort(key=lambda x: x["confirmations"], reverse=True) - oldest = aged[0] - newest = aged[-1] - spread = oldest["confirmations"] - newest["confirmations"] - - if spread < 10: - ok(f"UTXO age spread is small ({spread} blocks). No dormancy pattern.") - return - - finding({ - "type": "UTXO_AGE_SPREAD", - "severity": "LOW", - "description": f"UTXO age spread of {spread} blocks between oldest and newest", - "details": { - "spread_blocks": spread, - "oldest": {"txid": oldest["utxo"]["txid"], "confirmations": oldest["confirmations"], "amount_btc": round(oldest["utxo"]["amount"], 8)}, - "newest": {"txid": newest["utxo"]["txid"], "confirmations": newest["confirmations"], "amount_btc": round(newest["utxo"]["amount"], 8)}, - }, - "correction": ( - "Prefer spending older UTXOs first (FIFO coin selection) to normalize the age distribution of your " - "UTXO set and avoid leaving very old coins as obvious dormancy markers. " - "Alternatively, route very old UTXOs through a CoinJoin to reset their history before spending. " - "Avoid holding large numbers of long-dormant coins in the same wallet as freshly received funds." - ), - }) - - OLD_THRESHOLD = 100 # blocks - old_utxos = [a for a in aged if a["confirmations"] >= OLD_THRESHOLD] - if old_utxos: - warn({ - "type": "DORMANT_UTXOS", - "severity": "LOW", - "description": f"{len(old_utxos)} UTXO(s) have ≥{OLD_THRESHOLD} confirmations (dormant/hoarded coins pattern)", - "details": { - "count": len(old_utxos), - "threshold_blocks": OLD_THRESHOLD, - }, - }) - - -def detect_10_exchange_origin(g: TxGraph, known_exchange_wallets=None): - """Detect UTXOs that likely originated from exchange batch withdrawals.""" - section("10 · Probable Exchange Origin") - - # Build set of known exchange txids if wallet names provided - exchange_txids = set() - if known_exchange_wallets: - for ew in known_exchange_wallets: - try: - etxs = cli("listtransactions", "*", 10000, 0, "true", wallet=ew) - for etx in (etxs or []): - if etx.get("txid"): - exchange_txids.add(etx["txid"]) - except Exception: - pass - - BATCH_THRESHOLD = 5 # ≥5 outputs = likely batch withdrawal - found_any = False - - for txid in g.our_txids: - tx = g.fetch_tx(txid) - if not tx: - continue - - n_out = len(tx.get("vout", [])) - if n_out < BATCH_THRESHOLD: - continue - - # Check: do we RECEIVE in this tx? (we're a recipient, not sender) - our_inputs = [ia for ia in g.get_input_addresses(txid) if g.is_ours(ia["address"])] - our_outputs = [o for o in g.get_output_addresses(txid) if g.is_ours(o["address"])] - - if our_inputs: - # We're a sender in a many-output TX — that's OUR batch, not exchange - continue - - if not our_outputs: - continue - - # Heuristics for exchange batch - signals = [] - - # 1. High output count - signals.append(f"High output count: {n_out}") - - # 2. Many unique addresses - unique_addrs = set() - for vout in tx["vout"]: - a = vout.get("scriptPubKey", {}).get("address", "") - if a: - unique_addrs.add(a) - if len(unique_addrs) >= BATCH_THRESHOLD: - signals.append(f"{len(unique_addrs)} unique recipient addresses") - - # 3. Known exchange wallet - if txid in exchange_txids: - signals.append("TX matches known exchange wallet history") - - # 4. Large input relative to individual outputs - input_addrs = g.get_input_addresses(txid) - input_total = sum(ia["value"] for ia in input_addrs) - output_vals = sorted(v.get("value", 0) for v in tx["vout"]) - if output_vals: - median_out = output_vals[len(output_vals) // 2] - if median_out > 0: - ratio = input_total / median_out - if ratio > 10: - signals.append(f"Input/median-output ratio: {ratio:.0f}x (hot wallet pattern)") - - if len(signals) >= 2: - found_any = True - finding({ - "type": "EXCHANGE_ORIGIN", - "severity": "MEDIUM", - "description": f"TX {txid} looks like an exchange batch withdrawal ({len(signals)} signal(s))", - "details": { - "txid": txid, - "signals": signals, - "received_outputs": [{"address": o["address"], "amount_btc": round(o["value"], 8)} for o in our_outputs], - }, - "correction": ( - "Withdraw via Lightning Network instead of on-chain to avoid the exchange-origin fingerprint entirely. " - "If an on-chain withdrawal is required, request it at a non-standard time or amount to reduce " - "correlation with a specific batch. " - "After withdrawal, pass the UTXO through a CoinJoin before using it for other payments, so the " - "exchange link is severed from your subsequent spending history." - ), - }) - - if not found_any: - ok("No exchange-origin batch patterns detected.") - - -def detect_11_tainted_utxos(g: TxGraph, known_risky_wallets=None): - """Detect UTXOs that have taint from known risky sources.""" - section("11 · Tainted UTXOs / Risky Source Exposure") - - if not known_risky_wallets: - info("No --known-risky-wallets provided. Skipping taint analysis.") - info("(Provide wallet names to enable: --known-risky-wallets risky)") - ok("Taint detection requires known-risky wallet metadata.") - return - - # Build set of risky TXIDs - risky_txids = set() - for rw in known_risky_wallets: - try: - rtxs = cli("listtransactions", "*", 10000, 0, "true", wallet=rw) - for rtx in (rtxs or []): - if rtx.get("txid"): - risky_txids.add(rtx["txid"]) - except Exception: - info(f"Could not read wallet '{rw}'") - - if not risky_txids: - info("No transactions found in risky wallets.") - return - - found_any = False - - for txid in g.our_txids: - input_addrs = g.get_input_addresses(txid) - our_in = [ia for ia in input_addrs if g.is_ours(ia["address"])] - if not our_in or len(input_addrs) < 2: - continue - - tainted = [] - clean = [] - for ia in input_addrs: - # An input is tainted if its funding TX is in a risky wallet's history - if ia["txid"] in risky_txids: - tainted.append(ia) - else: - clean.append(ia) - - if tainted and clean: - found_any = True - taint_pct = len(tainted) / len(input_addrs) * 100 - finding({ - "type": "TAINTED_UTXO_MERGE", - "severity": "HIGH", - "description": f"TX {txid} merges {len(tainted)} tainted + {len(clean)} clean inputs ({round(taint_pct)}% taint)", - "details": { - "txid": txid, - "tainted_inputs": [{"address": t["address"], "amount_btc": round(t["value"], 8), "source_txid": t["txid"]} for t in tainted], - "clean_inputs": [{"address": c["address"], "amount_btc": round(c["value"], 8)} for c in clean], - "taint_pct": round(taint_pct), - }, - "correction": ( - "Immediately freeze tainted UTXOs in your wallet to prevent them from being spent alongside clean funds. " - "Never merge inputs from known risky sources with unrelated UTXOs — this propagates the taint to all outputs. " - "Seek legal/compliance guidance on whether the tainted funds can be returned or must be reported. " - "If the funds are legitimately yours, process the tainted UTXO separately and consider disclosing " - "its origin to any counterparty that may receive it downstream." - ), - }) - - # Also check: did we receive directly from a risky source? - for txid in g.our_txids: - if txid in risky_txids: - our_outs = [o for o in g.get_output_addresses(txid) if g.is_ours(o["address"])] - if our_outs: - found_any = True - warn({ - "type": "DIRECT_TAINT", - "severity": "HIGH", - "description": f"TX {txid} is directly from a known risky source", - "details": { - "txid": txid, - "received_outputs": [{"address": o["address"], "amount_btc": round(o["value"], 8)} for o in our_outs], - }, - }) - - if not found_any: - ok("No tainted UTXO merges detected.") - - -def detect_12_behavioral_fingerprint(g: TxGraph): - """ - Analyze the descriptor's transaction set for patterns that make the user - identifiable through behavioral consistency. - - We evaluate OBJECTIVE, measurable features that chain analysis firms - actually use to cluster and fingerprint wallets. - """ - section("12 · Behavioral Fingerprint Analysis") - - # Collect send transactions (where we have inputs) - send_txids = [] - for txid in g.our_txids: - input_addrs = g.get_input_addresses(txid) - our_in = [ia for ia in input_addrs if g.is_ours(ia["address"])] - if our_in: - send_txids.append(txid) - - if len(send_txids) < 3: - ok(f"Only {len(send_txids)} send transactions — not enough data for fingerprinting.") - return - - # ── Feature extraction ── - output_counts = [] - payment_amounts_sats = [] - change_amounts_sats = [] - input_script_types = [] - output_script_types = [] - rbf_signals = [] - locktime_values = [] - fee_rates = [] # sat/vB - n_inputs_list = [] - uses_round_amounts = 0 - total_payments = 0 - change_address_types_used = set() - payment_address_types_used = set() - version_numbers = set() - - for txid in send_txids: - tx = g.fetch_tx(txid) - if not tx: - continue - - n_in = len(tx.get("vin", [])) - n_out = len(tx.get("vout", [])) - n_inputs_list.append(n_in) - output_counts.append(n_out) - - # Version - version_numbers.add(tx.get("version", 2)) - - # Locktime - locktime_values.append(tx.get("locktime", 0)) - - # RBF signalling - for vin in tx.get("vin", []): - seq = vin.get("sequence", 0xffffffff) - rbf_signals.append(seq < 0xfffffffe) - - # Input script types - for ia in g.get_input_addresses(txid): - if g.is_ours(ia["address"]): - input_script_types.append(g.get_script_type(ia["address"])) - - # Output analysis - outputs = g.get_output_addresses(txid) - for out in outputs: - sats = int(round(out["value"] * 1e8)) - if g.is_ours(out["address"]): - # Change output - change_amounts_sats.append(sats) - change_address_types_used.add(out["type"]) - else: - # Payment output - payment_amounts_sats.append(sats) - output_script_types.append(out["type"]) - payment_address_types_used.add(out["type"]) - total_payments += 1 - if sats > 0 and (sats % 100000 == 0 or sats % 1000000 == 0): - uses_round_amounts += 1 - - # Fee rate - if "vsize" in tx and tx["vsize"] > 0: - # Compute fee from inputs - outputs - in_total = sum(ia["value"] for ia in g.get_input_addresses(txid)) - out_total = sum(v.get("value", 0) for v in tx["vout"]) - fee_sats = int(round((in_total - out_total) * 1e8)) - if fee_sats > 0: - fee_rates.append(fee_sats / tx["vsize"]) - - # ── Analysis ── - problems = [] - - # 1. Round amount usage pattern - if total_payments > 0: - round_pct = uses_round_amounts / total_payments * 100 - if round_pct > 60: - problems.append( - f"Round payment amounts: {round_pct:.0f}% of payments are round numbers. " - "This is a distinctive behavioral pattern that aids clustering." - ) - - # 2. Consistent output count (always 2 outputs = simple spend pattern) - if output_counts: - avg_outs = sum(output_counts) / len(output_counts) - if all(c == output_counts[0] for c in output_counts) and len(output_counts) >= 3: - problems.append( - f"Uniform output count: all {len(output_counts)} send TXs have exactly " - f"{output_counts[0]} outputs. Consistent structure aids fingerprinting." - ) - - # 3. Script type consistency or mixing - input_types_set = set(input_script_types) - if len(input_types_set) > 1: - problems.append( - f"Mixed input script types used across TXs: {input_types_set}. " - "Mixing address families is rare and highly identifying." - ) - elif len(input_types_set) == 1 and input_script_types: - t = input_types_set.pop() - if t == "p2pkh": - problems.append( - f"All inputs use legacy P2PKH — a very uncommon script type today. " - "This alone narrows your anonymity set significantly." - ) - - # 4. RBF signaling consistency - if rbf_signals: - rbf_pct = sum(rbf_signals) / len(rbf_signals) * 100 - if rbf_pct == 100: - problems.append( - f"RBF always enabled: 100% of inputs signal replace-by-fee. " - "While increasingly common, it's a distinguishing feature vs non-RBF wallets." - ) - elif rbf_pct == 0: - problems.append( - "RBF never enabled: 0% of inputs signal replace-by-fee. " - "This is uncommon in modern wallets and distinguishes your software." - ) - - # 5. Locktime pattern - if locktime_values: - nonzero_lt = [lt for lt in locktime_values if lt > 0] - if len(nonzero_lt) == len(locktime_values) and len(locktime_values) >= 3: - problems.append( - "Anti-fee-sniping locktime always set — consistent with Bitcoin Core / Electrum. " - "Absence or presence of this reveals your wallet software." - ) - elif not nonzero_lt and len(locktime_values) >= 3: - problems.append( - "Locktime always 0 — no anti-fee-sniping. " - "This distinguishes your wallet from Bitcoin Core / Electrum defaults." - ) - - # 6. Fee rate consistency - if len(fee_rates) >= 3: - avg_fee = sum(fee_rates) / len(fee_rates) - if avg_fee > 0: - variance = sum((f - avg_fee) ** 2 for f in fee_rates) / len(fee_rates) - stddev = variance ** 0.5 - cv = stddev / avg_fee # coefficient of variation - if cv < 0.15: - problems.append( - f"Very consistent fee rate: avg {avg_fee:.1f} sat/vB ± {stddev:.1f} " - f"(CV={cv:.2f}). Low variance suggests fixed-fee-rate wallet configuration." - ) - - # 7. Change address type pattern - if change_address_types_used and payment_address_types_used: - if change_address_types_used != payment_address_types_used: - # This leaks which outputs are change - problems.append( - f"Change uses different script type ({change_address_types_used}) " - f"than payments ({payment_address_types_used}) — trivially identifies change outputs." - ) - - # 8. Input count pattern (always 1 input = no consolidation; always many = distinctive) - if n_inputs_list and len(n_inputs_list) >= 3: - if all(n == 1 for n in n_inputs_list): - pass # normal, not distinctive - elif all(n == n_inputs_list[0] for n in n_inputs_list) and n_inputs_list[0] > 1: - problems.append( - f"Always uses exactly {n_inputs_list[0]} inputs per TX — unusual and identifying." - ) - - # ── Report ── - if not problems: - ok(f"Analyzed {len(send_txids)} transactions. No strong behavioral fingerprints detected.") - return - - finding({ - "type": "BEHAVIORAL_FINGERPRINT", - "severity": "MEDIUM", - "description": f"Behavioral fingerprint detected across {len(send_txids)} send transactions ({len(problems)} pattern(s))", - "details": { - "send_tx_count": len(send_txids), - "patterns": problems, - }, - "correction": ( - "Switch to wallet software that applies anti-fingerprinting defaults: anti-fee-sniping locktime, " - "randomized fee rates (not fixed sat/vB), and RBF enabled by default. " - "Avoid sending only round amounts — add small random satoshi offsets to payment values. " - "Standardize on a single modern script type (Taproot) so your input-type set is not distinctive. " - "Use batched payments sparingly and vary the number of outputs per transaction to prevent " - "structural fingerprinting from consistent output counts." - ), - }) - - -# ═══════════════════════════════════════════════════════════════════════════════ -# 4. MAIN -# ═══════════════════════════════════════════════════════════════════════════════ - -def main(): - parser = argparse.ArgumentParser( - description="Detect Bitcoin privacy vulnerabilities from output descriptors.", - epilog="Examples:\n" - " python3 detect.py --wallet alice\n" - ' python3 detect.py --wallet alice --known-risky-wallets risky\n' - ' python3 detect.py "wpkh(tpub.../0/*)#chk" "wpkh(tpub.../1/*)#chk"\n', - formatter_class=argparse.RawDescriptionHelpFormatter, - ) - parser.add_argument("descriptors", nargs="*", help="Output descriptors to scan") - parser.add_argument("--wallet", "-w", help="Read descriptors from an existing wallet") - parser.add_argument("--known-risky-wallets", nargs="*", default=None, - help="Wallet names whose TXIDs are considered tainted") - parser.add_argument("--known-exchange-wallets", nargs="*", default=None, - help="Wallet names whose TXIDs are considered exchange-origin") - parser.add_argument("--keep-scan-wallet", action="store_true", - help="Don't delete the temporary scan wallet after running") - args = parser.parse_args() - - if not args.wallet and not args.descriptors: - parser.error("Provide either --wallet or one or more descriptors.") - - # ── Step 1: Resolve descriptors ── - section("Setup: Resolving Descriptors") - descriptors = resolve_descriptors(args) - info(f"Found {len(descriptors)} descriptors") - for d in descriptors: - dtype = d["desc"].split("(")[0] - role = "internal/change" if d["internal"] else "external/receive" - info(f" {dtype:15} {role:20} range [0..{d['range_end']}]") - - # ── Step 2: Derive all addresses ── - section("Setup: Deriving Addresses") - addr_map = derive_all_addresses(descriptors) - info(f"Derived {len(addr_map)} addresses across all descriptor types") - - # Count by type - type_counts = defaultdict(int) - for meta in addr_map.values(): - type_counts[meta["type"]] += 1 - for t, c in sorted(type_counts.items()): - info(f" {t}: {c} addresses") - - # ── Step 3: Build watch-only wallet ── - section("Setup: Building Scan Wallet") - scan_wallet = "_detect_scan" - if args.wallet: - # If they gave us a wallet, just use it directly — faster, no rescan needed - scan_wallet = args.wallet - info(f"Using existing wallet '{scan_wallet}' directly (no rescan needed)") - else: - scan_wallet = build_scan_wallet(descriptors) - info(f"Created temporary watch-only wallet '{scan_wallet}' with full rescan") - - # ── Step 4: Gather transaction history ── - section("Setup: Loading Transaction History") - wallet_txs = get_all_transactions(scan_wallet) - utxos = get_all_utxos(scan_wallet) - info(f"Transaction history: {len(wallet_txs)} entries") - info(f"Current UTXOs: {len(utxos)}") - - if not wallet_txs: - print(json.dumps({"error": "No transactions found for these descriptors."})) - return - - # ── Step 5: Build transaction graph ── - g = TxGraph(addr_map, wallet_txs, utxos) - info(f"Unique transaction IDs: {len(g.our_txids)}") - - # ── Step 6: Run all detectors ── - detect_01_address_reuse(g) - detect_02_cioh(g) - detect_03_dust(g) - detect_04_dust_spending(g) - detect_05_change_detection(g) - detect_06_consolidation_origin(g) - detect_07_script_type_mixing(g) - detect_08_cluster_merge(g) - detect_09_lookback_depth(g) - detect_10_exchange_origin(g, args.known_exchange_wallets) - detect_11_tainted_utxos(g, args.known_risky_wallets) - detect_12_behavioral_fingerprint(g) - - # ── JSON output ── - report = { - "stats": { - "transactions_analyzed": len(g.our_txids), - "addresses_derived": len(addr_map), - }, - "findings": FINDINGS, - "warnings": WARNINGS, - "summary": { - "findings": len(FINDINGS), - "warnings": len(WARNINGS), - "clean": len(FINDINGS) == 0 and len(WARNINGS) == 0, - }, - } - print(json.dumps(report, indent=2)) - - # Cleanup - if not args.wallet and not args.keep_scan_wallet: - try: - cli("unloadwallet", "_detect_scan") - except Exception: - pass - - -if __name__ == "__main__": - main() diff --git a/backend/script/miner b/backend/script/miner deleted file mode 100755 index f46d88b..0000000 --- a/backend/script/miner +++ /dev/null @@ -1,604 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2020-present The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -import argparse -import json -import logging -import math -import os -import re -import shlex -import sys -import time -import subprocess - -PATH_BASE_CONTRIB_SIGNET = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) -PATH_BASE_TEST_FUNCTIONAL = os.path.abspath(os.path.join(PATH_BASE_CONTRIB_SIGNET, "..", "..", "test", "functional")) -sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL) - -from test_framework.blocktools import get_witness_script, script_BIP34_coinbase_height, SIGNET_HEADER # noqa: E402 -from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_binary, from_hex, ser_string, ser_uint256, tx_from_hex, MAX_SEQUENCE_NONFINAL # noqa: E402 -from test_framework.psbt import PSBT, PSBTMap, PSBT_GLOBAL_UNSIGNED_TX, PSBT_IN_FINAL_SCRIPTSIG, PSBT_IN_FINAL_SCRIPTWITNESS, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_SIGHASH_TYPE # noqa: E402 -from test_framework.script import CScript, CScriptOp # noqa: E402 - -logging.basicConfig( - format='%(asctime)s %(levelname)s %(message)s', - level=logging.INFO, - datefmt='%Y-%m-%d %H:%M:%S') - -PSBT_SIGNET_BLOCK = b"\xfc\x06signetb" # proprietary PSBT global field holding the block being signed -RE_MULTIMINER = re.compile(r"^(\d+)(-(\d+))?/(\d+)$") - -def signet_txs(block, challenge): - # assumes signet solution has not been added yet so does not need - # to be removed - - txs = block.vtx[:] - txs[0] = CTransaction(txs[0]) - txs[0].vout[-1].scriptPubKey += CScriptOp.encode_op_pushdata(SIGNET_HEADER) - hashes = [] - for tx in txs: - hashes.append(ser_uint256(tx.txid_int)) - mroot = block.get_merkle_root(hashes) - - sd = b"" - sd += block.nVersion.to_bytes(4, "little", signed=True) - sd += ser_uint256(block.hashPrevBlock) - sd += ser_uint256(mroot) - sd += block.nTime.to_bytes(4, "little") - - to_spend = CTransaction() - to_spend.version = 0 - to_spend.nLockTime = 0 - to_spend.vin = [CTxIn(COutPoint(0, 0xFFFFFFFF), b"\x00" + CScriptOp.encode_op_pushdata(sd), 0)] - to_spend.vout = [CTxOut(0, challenge)] - - spend = CTransaction() - spend.version = 0 - spend.nLockTime = 0 - spend.vin = [CTxIn(COutPoint(to_spend.txid_int, 0), b"", 0)] - spend.vout = [CTxOut(0, b"\x6a")] - - return spend, to_spend - -def decode_challenge_psbt(b64psbt): - psbt = PSBT.from_base64(b64psbt) - - assert len(psbt.tx.vin) == 1 - assert len(psbt.tx.vout) == 1 - assert PSBT_SIGNET_BLOCK in psbt.g.map - return psbt - -def get_block_from_psbt(psbt): - return from_binary(CBlock, psbt.g.map[PSBT_SIGNET_BLOCK]) - -def get_solution_from_psbt(psbt, emptyok=False): - scriptSig = psbt.i[0].map.get(PSBT_IN_FINAL_SCRIPTSIG, b"") - scriptWitness = psbt.i[0].map.get(PSBT_IN_FINAL_SCRIPTWITNESS, b"\x00") - if emptyok and len(scriptSig) == 0 and scriptWitness == b"\x00": - return None - return ser_string(scriptSig) + scriptWitness - -def finish_block(block, signet_solution, grind_cmd): - if signet_solution is None: - pass # Don't need to add a signet commitment if there's no signet signature needed - else: - block.vtx[0].vout[-1].scriptPubKey += CScriptOp.encode_op_pushdata(SIGNET_HEADER + signet_solution) - block.hashMerkleRoot = block.calc_merkle_root() - if grind_cmd is None: - block.solve() - else: - headhex = CBlockHeader.serialize(block).hex() - cmd = shlex.split(grind_cmd) + [headhex] - newheadhex = subprocess.run(cmd, stdout=subprocess.PIPE, input=b"", check=True).stdout.strip() - newhead = from_hex(CBlockHeader(), newheadhex.decode('utf8')) - block.nNonce = newhead.nNonce - return block - -def new_block(tmpl, reward_spk, *, blocktime=None, poolid=None): - scriptSig = script_BIP34_coinbase_height(tmpl["height"]) - if poolid is not None: - scriptSig = CScript(b"" + scriptSig + CScriptOp.encode_op_pushdata(poolid)) - - cbtx = CTransaction() - cbtx.nLockTime = tmpl["height"] - 1 - cbtx.vin = [CTxIn(COutPoint(0, 0xffffffff), scriptSig, MAX_SEQUENCE_NONFINAL)] - cbtx.vout = [CTxOut(tmpl["coinbasevalue"], reward_spk)] - cbtx.vin[0].nSequence = 2**32-2 - - block = CBlock() - block.nVersion = tmpl["version"] - block.hashPrevBlock = int(tmpl["previousblockhash"], 16) - block.nTime = tmpl["curtime"] if blocktime is None else blocktime - if block.nTime < tmpl["mintime"]: - block.nTime = tmpl["mintime"] - block.nBits = int(tmpl["bits"], 16) - block.nNonce = 0 - block.vtx = [cbtx] + [tx_from_hex(t["data"]) for t in tmpl["transactions"]] - - witnonce = 0 - witroot = block.calc_witness_merkle_root() - cbwit = CTxInWitness() - cbwit.scriptWitness.stack = [ser_uint256(witnonce)] - block.vtx[0].wit.vtxinwit = [cbwit] - block.vtx[0].vout.append(CTxOut(0, bytes(get_witness_script(witroot, witnonce)))) - - block.hashMerkleRoot = block.calc_merkle_root() - - return block - -def generate_psbt(block, signet_spk): - signet_spk_bin = bytes.fromhex(signet_spk) - signme, spendme = signet_txs(block, signet_spk_bin) - psbt = PSBT() - psbt.g = PSBTMap( {PSBT_GLOBAL_UNSIGNED_TX: signme.serialize(), - PSBT_SIGNET_BLOCK: block.serialize() - } ) - psbt.i = [ PSBTMap( {PSBT_IN_NON_WITNESS_UTXO: spendme.serialize(), - PSBT_IN_SIGHASH_TYPE: bytes([1,0,0,0])}) - ] - psbt.o = [ PSBTMap() ] - return psbt.to_base64() - -def get_poolid(args): - if args.poolid is not None: - return args.poolid.encode('utf8') - elif args.poolnum is not None: - return b"/signet:%d/" % (args.poolnum) - else: - return None - -def get_reward_addr_spk(args, height): - assert args.address is not None or args.descriptor is not None - - if hasattr(args, "reward_spk"): - return args.address, args.reward_spk - - if args.address is not None: - reward_addr = args.address - elif '*' not in args.descriptor: - reward_addr = args.address = json.loads(args.bcli("deriveaddresses", args.descriptor))[0] - else: - remove = [k for k in args.derived_addresses.keys() if k+20 <= height] - for k in remove: - del args.derived_addresses[k] - if height not in args.derived_addresses: - addrs = json.loads(args.bcli("deriveaddresses", args.descriptor, "[%d,%d]" % (height, height+20))) - for k, a in enumerate(addrs): - args.derived_addresses[height+k] = a - reward_addr = args.derived_addresses[height] - - reward_spk = bytes.fromhex(json.loads(args.bcli("getaddressinfo", reward_addr))["scriptPubKey"]) - if args.address is not None: - # will always be the same, so cache - args.reward_spk = reward_spk - - return reward_addr, reward_spk - -def do_genpsbt(args): - poolid = get_poolid(args) - tmpl = json.load(sys.stdin) - signet_spk = tmpl["signet_challenge"] - _, reward_spk = get_reward_addr_spk(args, tmpl["height"]) - block = new_block(tmpl, reward_spk, poolid=poolid) - psbt = generate_psbt(block, signet_spk) - print(psbt) - -def do_solvepsbt(args): - psbt = decode_challenge_psbt(sys.stdin.read()) - block = get_block_from_psbt(psbt) - signet_solution = get_solution_from_psbt(psbt, emptyok=True) - block = finish_block(block, signet_solution, args.grind_cmd) - print(block.serialize().hex()) - -def nbits_to_target(nbits): - shift = (nbits >> 24) & 0xff - return (nbits & 0x00ffffff) * 2**(8*(shift - 3)) - -def target_to_nbits(target): - tstr = "{0:x}".format(target) - if len(tstr) < 6: - tstr = ("000000"+tstr)[-6:] - if len(tstr) % 2 != 0: - tstr = "0" + tstr - if int(tstr[0],16) >= 0x8: - # avoid "negative" - tstr = "00" + tstr - fix = int(tstr[:6], 16) - sz = len(tstr)//2 - if tstr[6:] != "0"*(sz*2-6): - fix += 1 - - return int("%02x%06x" % (sz,fix), 16) - -def seconds_to_hms(s): - if s == 0: - return "0s" - neg = (s < 0) - if neg: - s = -s - out = "" - if s % 60 > 0: - out = "%ds" % (s % 60) - s //= 60 - if s % 60 > 0: - out = "%dm%s" % (s % 60, out) - s //= 60 - if s > 0: - out = "%dh%s" % (s, out) - if neg: - out = "-" + out - return out - -def trivial_challenge(spkhex): - """ - BIP325 allows omitting the signet commitment when scriptSig and - scriptWitness are both empty. This is the case for trivial - challenges such as OP_TRUE or a single data push. - """ - spk = bytes.fromhex(spkhex) - if len(spk) == 1 and 0x51 <= spk[0] <= 0x60: - # OP_TRUE/OP_1...OP_16 - return True - elif 2 <= len(spk) <= 76 and spk[0] + 1 == len(spk): - # Single fixed push of 1-75 bytes - return True - return False - -class Generate: - INTERVAL = 600.0*2016/2015 # 10 minutes, adjusted for the off-by-one bug - - - def __init__(self, multiminer=None, ultimate_target=None, poisson=False, max_interval=1800, - standby_delay=0, backup_delay=0, set_block_time=None, - poolid=None): - if multiminer is None: - multiminer = (0, 1, 1) - (self.multi_low, self.multi_high, self.multi_period) = multiminer - self.ultimate_target = ultimate_target - self.poisson = poisson - self.max_interval = max_interval - self.standby_delay = standby_delay - self.backup_delay = backup_delay - self.set_block_time = set_block_time - self.poolid = poolid - - def next_block_delta(self, last_nbits, last_hash): - # strategy: - # 1) work out how far off our desired target we are - # 2) cap it to a factor of 4 since that's the best we can do in a single retarget period - # 3) use that to work out the desired average interval in this retarget period - # 4) if doing poisson, use the last hash to pick a uniformly random number in [0,1), and work out a random multiplier to vary the average by - # 5) cap the resulting interval between 1 second and 1 hour to avoid extremes - - current_target = nbits_to_target(last_nbits) - retarget_factor = self.ultimate_target / current_target - retarget_factor = max(0.25, min(retarget_factor, 4.0)) - - avg_interval = self.INTERVAL * retarget_factor - - if self.poisson: - det_rand = int(last_hash[-8:], 16) * 2**-32 - this_interval_variance = -math.log1p(-det_rand) - else: - this_interval_variance = 1 - - this_interval = avg_interval * this_interval_variance - this_interval = max(1, min(this_interval, self.max_interval)) - - return this_interval - - def next_block_is_mine(self, last_hash): - det_rand = int(last_hash[-16:-8], 16) - return self.multi_low <= (det_rand % self.multi_period) < self.multi_high - - def next_block_time(self, now, bestheader, is_first_block): - if self.set_block_time is not None: - logging.debug("Setting start time to %d", self.set_block_time) - self.mine_time = self.set_block_time - self.action_time = now - self.is_mine = True - elif bestheader["height"] == 0: - time_delta = self.INTERVAL * 100 # plenty of time to mine 100 blocks - logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60)) - self.mine_time = now - time_delta - self.action_time = now - self.is_mine = True - else: - time_delta = self.next_block_delta(int(bestheader["bits"], 16), bestheader["hash"]) - self.mine_time = bestheader["time"] + time_delta - - self.is_mine = self.next_block_is_mine(bestheader["hash"]) - - self.action_time = self.mine_time - if not self.is_mine: - self.action_time += self.backup_delay - - if self.standby_delay > 0: - self.action_time += self.standby_delay - elif is_first_block: - # for non-standby, always mine immediately on startup, - # even if the next block shouldn't be ours - self.action_time = now - - # don't want fractional times so round down - self.mine_time = int(self.mine_time) - self.action_time = int(self.action_time) - - # can't mine a block 2h in the future; 1h55m for some safety - self.action_time = max(self.action_time, self.mine_time - 6900) - - def gbt(self, bcli, bestblockhash, now): - tmpl = json.loads(bcli("getblocktemplate", '{"rules":["signet","segwit"]}')) - if tmpl["previousblockhash"] != bestblockhash: - logging.warning("GBT based off unexpected block (%s not %s), retrying", tmpl["previousblockhash"], bci["bestblockhash"]) - time.sleep(1) - return None - - if tmpl["mintime"] > self.mine_time: - logging.info("Updating block time from %d to %d", self.mine_time, tmpl["mintime"]) - self.mine_time = tmpl["mintime"] - if self.mine_time > now: - logging.error("GBT mintime is in the future: %d is %d seconds later than %d", self.mine_time, (self.mine_time-now), now) - return None - - return tmpl - - def mine(self, bcli, grind_cmd, tmpl, reward_spk): - block = new_block(tmpl, reward_spk, blocktime=self.mine_time, poolid=self.poolid) - - signet_spk = tmpl["signet_challenge"] - if trivial_challenge(signet_spk): - signet_solution = None - else: - psbt = generate_psbt(block, signet_spk) - input_stream = os.linesep.join([psbt, "true", "ALL"]).encode('utf8') - psbt_signed = json.loads(bcli("-stdin", "walletprocesspsbt", input=input_stream)) - if not psbt_signed.get("complete",False): - logging.debug("Generated PSBT: %s" % (psbt,)) - sys.stderr.write("PSBT signing failed\n") - return None - psbt = decode_challenge_psbt(psbt_signed["psbt"]) - signet_solution = get_solution_from_psbt(psbt) - - return finish_block(block, signet_solution, grind_cmd) - -def do_generate(args): - if args.set_block_time is not None: - max_blocks = 1 - elif args.max_blocks is not None: - if args.max_blocks < 1: - logging.error("--max_blocks must specify a positive integer") - return 1 - max_blocks = args.max_blocks - elif args.ongoing: - max_blocks = None - else: - max_blocks = 1 - - if args.set_block_time is not None and args.set_block_time < 0: - args.set_block_time = time.time() - logging.info("Treating negative block time as current time (%d)" % (args.set_block_time)) - - if args.min_nbits: - args.nbits = "1e0377ae" - logging.info("Using nbits=%s" % (args.nbits)) - - if args.set_block_time is None: - if args.nbits is None or len(args.nbits) != 8: - logging.error("Must specify --nbits (use calibrate command to determine value)") - return 1 - - if args.multiminer is None: - my_blocks = (0,1,1) - else: - if not args.ongoing: - logging.error("Cannot specify --multiminer without --ongoing") - return 1 - m = RE_MULTIMINER.match(args.multiminer) - if m is None: - logging.error("--multiminer argument must be k/m or j-k/m") - return 1 - start,_,stop,total = m.groups() - if stop is None: - stop = start - start, stop, total = map(int, (start, stop, total)) - if stop < start or start <= 0 or total < stop or total == 0: - logging.error("Inconsistent values for --multiminer") - return 1 - my_blocks = (start-1, stop, total) - - if args.max_interval < 960: - logging.error("--max-interval must be at least 960 (16 minutes)") - return 1 - - poolid = get_poolid(args) - - ultimate_target = nbits_to_target(int(args.nbits,16)) - - gen = Generate(multiminer=my_blocks, ultimate_target=ultimate_target, poisson=args.poisson, max_interval=args.max_interval, - standby_delay=args.standby_delay, backup_delay=args.backup_delay, set_block_time=args.set_block_time, poolid=poolid) - - mined_blocks = 0 - bestheader = {"hash": None} - lastheader = None - while max_blocks is None or mined_blocks < max_blocks: - - # current status? - bci = json.loads(args.bcli("getblockchaininfo")) - - if bestheader["hash"] != bci["bestblockhash"]: - bestheader = json.loads(args.bcli("getblockheader", bci["bestblockhash"])) - - if lastheader is None: - lastheader = bestheader["hash"] - elif bestheader["hash"] != lastheader: - next_delta = gen.next_block_delta(int(bestheader["bits"], 16), bestheader["hash"]) - next_delta += bestheader["time"] - time.time() - next_is_mine = gen.next_block_is_mine(bestheader["hash"]) - logging.info("Received new block at height %d; next in %s (%s)", bestheader["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup")) - lastheader = bestheader["hash"] - - # when is the next block due to be mined? - now = time.time() - gen.next_block_time(now, bestheader, (mined_blocks == 0)) - - # ready to go? otherwise sleep and check for new block - if now < gen.action_time: - sleep_for = min(gen.action_time - now, 60) - if gen.mine_time < now: - # someone else might have mined the block, - # so check frequently, so we don't end up late - # mining the next block if it's ours - sleep_for = min(20, sleep_for) - minestr = "mine" if gen.is_mine else "backup" - logging.debug("Sleeping for %s, next block due in %s (%s)" % (seconds_to_hms(sleep_for), seconds_to_hms(gen.mine_time - now), minestr)) - time.sleep(sleep_for) - continue - - # gbt - tmpl = gen.gbt(args.bcli, bci["bestblockhash"], now) - if tmpl is None: - continue - - logging.debug("GBT template: %s", tmpl) - - # address for reward - reward_addr, reward_spk = get_reward_addr_spk(args, tmpl["height"]) - - # mine block - logging.debug("Mining block delta=%s start=%s mine=%s", seconds_to_hms(gen.mine_time-bestheader["time"]), gen.mine_time, gen.is_mine) - mined_blocks += 1 - block = gen.mine(args.bcli, args.grind_cmd, tmpl, reward_spk) - if block is None: - return 1 - - # submit block - r = args.bcli("-stdin", "submitblock", input=block.serialize().hex().encode('utf8')) - - # report - bstr = "block" if gen.is_mine else "backup block" - - next_delta = gen.next_block_delta(block.nBits, block.hash_hex) - next_delta += block.nTime - time.time() - next_is_mine = gen.next_block_is_mine(block.hash_hex) - - logging.debug("Block hash %s payout to %s", block.hash_hex, reward_addr) - logging.info("Mined %s at height %d; next in %s (%s)", bstr, tmpl["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup")) - if r != "": - logging.warning("submitblock returned %s for height %d hash %s", r, tmpl["height"], block.hash_hex) - lastheader = block.hash_hex - -def do_calibrate(args): - if args.nbits is not None and args.seconds is not None: - sys.stderr.write("Can only specify one of --nbits or --seconds\n") - return 1 - if args.nbits is not None and len(args.nbits) != 8: - sys.stderr.write("Must specify 8 hex digits for --nbits\n") - return 1 - - TRIALS = 600 # gets variance down pretty low - TRIAL_BITS = 0x1e3ea75f # takes about 5m to do 600 trials - - header = CBlockHeader() - header.nBits = TRIAL_BITS - targ = nbits_to_target(header.nBits) - - start = time.time() - count = 0 - for i in range(TRIALS): - header.nTime = i - header.nNonce = 0 - headhex = header.serialize().hex() - cmd = shlex.split(args.grind_cmd) + [headhex] - newheadhex = subprocess.run(cmd, stdout=subprocess.PIPE, input=b"", check=True).stdout.strip() - - avg = (time.time() - start) * 1.0 / TRIALS - - if args.nbits is not None: - want_targ = nbits_to_target(int(args.nbits,16)) - want_time = avg*targ/want_targ - else: - want_time = args.seconds if args.seconds is not None else 25 - want_targ = int(targ*(avg/want_time)) - - print("nbits=%08x for %ds average mining time" % (target_to_nbits(want_targ), want_time)) - return 0 - -def bitcoin_cli(basecmd, args, **kwargs): - cmd = basecmd + ["-signet"] + args - logging.debug("Calling bitcoin-cli: %r", cmd) - out = subprocess.run(cmd, stdout=subprocess.PIPE, **kwargs, check=True).stdout - if isinstance(out, bytes): - out = out.decode('utf8') - return out.strip() - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--cli", default="bitcoin-cli", type=str, help="bitcoin-cli command") - parser.add_argument("--debug", action="store_true", help="Print debugging info") - parser.add_argument("--quiet", action="store_true", help="Only print warnings/errors") - - cmds = parser.add_subparsers(help="sub-commands") - genpsbt = cmds.add_parser("genpsbt", help="Generate a block PSBT for signing") - genpsbt.set_defaults(fn=do_genpsbt) - - solvepsbt = cmds.add_parser("solvepsbt", help="Solve a signed block PSBT") - solvepsbt.set_defaults(fn=do_solvepsbt) - - generate = cmds.add_parser("generate", help="Mine blocks") - generate.set_defaults(fn=do_generate) - howmany = generate.add_mutually_exclusive_group() - howmany.add_argument("--ongoing", action="store_true", help="Keep mining blocks") - howmany.add_argument("--max-blocks", default=None, type=int, help="Max blocks to mine (default=1)") - howmany.add_argument("--set-block-time", default=None, type=int, help="Set block time (unix timestamp); implies --max-blocks=1") - nbit_target = generate.add_mutually_exclusive_group() - nbit_target.add_argument("--nbits", default=None, type=str, help="Target nBits (specify difficulty)") - nbit_target.add_argument("--min-nbits", action="store_true", help="Target minimum nBits (use min difficulty)") - generate.add_argument("--poisson", action="store_true", help="Simulate randomised block times") - generate.add_argument("--multiminer", default=None, type=str, help="Specify which set of blocks to mine (eg: 1-40/100 for the first 40%%, 2/3 for the second 3rd)") - generate.add_argument("--backup-delay", default=300, type=int, help="Seconds to delay before mining blocks reserved for other miners (default=300)") - generate.add_argument("--standby-delay", default=0, type=int, help="Seconds to delay before mining blocks (default=0)") - generate.add_argument("--max-interval", default=1800, type=int, help="Maximum interblock interval (seconds)") - - calibrate = cmds.add_parser("calibrate", help="Calibrate difficulty") - calibrate.set_defaults(fn=do_calibrate) - calibrate_by = calibrate.add_mutually_exclusive_group() - calibrate_by.add_argument("--nbits", type=str, default=None) - calibrate_by.add_argument("--seconds", type=int, default=None) - - for sp in [genpsbt, generate]: - payto = sp.add_mutually_exclusive_group(required=True) - payto.add_argument("--address", default=None, type=str, help="Address for block reward payment") - payto.add_argument("--descriptor", default=None, type=str, help="Descriptor for block reward payment") - pool = sp.add_mutually_exclusive_group() - pool.add_argument("--poolnum", default=None, type=int, help="Identify blocks that you mine") - pool.add_argument("--poolid", default=None, type=str, help="Identify blocks that you mine (eg: /signet:1/)") - - for sp in [solvepsbt, generate, calibrate]: - sp.add_argument("--grind-cmd", default=None, type=str, required=(sp==calibrate), help="Command to grind a block header for proof-of-work") - - args = parser.parse_args(sys.argv[1:]) - - args.bcli = lambda *a, input=b"", **kwargs: bitcoin_cli(shlex.split(args.cli), list(a), input=input, **kwargs) - - if hasattr(args, "address") and hasattr(args, "descriptor"): - args.derived_addresses = {} - - if args.debug: - logging.getLogger().setLevel(logging.DEBUG) - elif args.quiet: - logging.getLogger().setLevel(logging.WARNING) - else: - logging.getLogger().setLevel(logging.INFO) - - if hasattr(args, "fn"): - return args.fn(args) - else: - logging.error("Must specify command") - return 1 - -if __name__ == "__main__": - main() diff --git a/backend/script/reproduce.py b/backend/script/reproduce.py deleted file mode 100644 index eeb1449..0000000 --- a/backend/script/reproduce.py +++ /dev/null @@ -1,418 +0,0 @@ -#!/usr/bin/env python3 -""" -reproduce.py -============ -Reproduces 12 Bitcoin privacy vulnerabilities on a local custom Signet. -Each run creates NEW on-chain transactions that exhibit the vulnerability. -No detection logic — that lives in detect.py. - -Usage: - python3 reproduce.py # Create all 12 vulnerability scenarios - python3 reproduce.py -k 3 # Create only vulnerability 3 -""" - -import sys -import os -import json -import time - -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) -from bitcoin_rpc import ( - cli, mine_blocks, get_tx, get_utxos, get_balance, - get_new_address, send_to_address, create_raw_tx, sign_raw_tx, - send_raw, get_block_count, create_funded_psbt, - process_psbt, finalize_psbt, -) - -# ═══════════════════════════════════════════════════════════════════════════════ -# Formatting helpers -# ═══════════════════════════════════════════════════════════════════════════════ -G = "\033[92m"; Y = "\033[93m"; C = "\033[96m"; B = "\033[1m"; R = "\033[0m" - -def header(num, title): - print(f"\n{'═'*78}") - print(f"{B}{C} REPRODUCE {num}: {title}{R}") - print(f"{'═'*78}") - -def ok(msg): - print(f" {G}✓{R} {msg}") - -def info(msg): - print(f" {Y}ℹ{R} {msg}") - -def ensure_funds(wallet, min_btc=0.5): - bal = get_balance(wallet) - if bal < min_btc: - addr = get_new_address(wallet, "bech32") - send_to_address("miner", addr, min_btc + 0.5) - mine_blocks(1) - -def mine_and_confirm(): - mine_blocks(1) - time.sleep(0.5) - -# ═══════════════════════════════════════════════════════════════════════════════ -# 1. Address Reuse -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_01(): - header(1, "Address Reuse") - ensure_funds("bob", 1.0) - reused_addr = get_new_address("alice", "bech32") - txid1 = send_to_address("bob", reused_addr, 0.01) - txid2 = send_to_address("bob", reused_addr, 0.02) - mine_and_confirm() - ok(f"Sent to same address {reused_addr} twice: TX {txid1[:16]}… and {txid2[:16]}…") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 2. Multi-input / CIOH -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_02(): - header(2, "Multi-input / CIOH (Common Input Ownership Heuristic)") - ensure_funds("bob", 2.0) - for _ in range(5): - addr = get_new_address("alice", "bech32") - send_to_address("bob", addr, 0.005) - mine_and_confirm() - - utxos = get_utxos("alice", 1) - small = [u for u in utxos if 0.004 < u["amount"] < 0.006][:5] - if len(small) < 2: - info("Not enough small UTXOs, skipping consolidation step") - return - inputs = [{"txid": u["txid"], "vout": u["vout"]} for u in small] - dest = get_new_address("bob", "bech32") - total = sum(u["amount"] for u in small) - psbt_result = create_funded_psbt( - "alice", inputs, [{dest: round(total - 0.001, 8)}], - {"subtractFeeFromOutputs": [0], "add_inputs": False} - ) - signed = process_psbt("alice", psbt_result["psbt"]) - final = finalize_psbt(signed["psbt"]) - txid = send_raw(final["hex"]) - mine_and_confirm() - ok(f"Consolidated {len(small)} inputs in TX {txid[:16]}… (CIOH trigger)") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 3. Dust UTXO Detection -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_03(): - header(3, "Dust UTXO Detection") - ensure_funds("bob", 1.0) - dust1 = get_new_address("alice", "bech32") - dust2 = get_new_address("alice", "bech32") - bob_utxos = get_utxos("bob", 1) - big = max(bob_utxos, key=lambda u: u["amount"]) - change = get_new_address("bob", "bech32") - change_amt = round(big["amount"] - 0.00001000 - 0.00000546 - 0.0001, 8) - raw = create_raw_tx( - [{"txid": big["txid"], "vout": big["vout"]}], - [{dust1: 0.00001000}, {dust2: 0.00000546}, {change: change_amt}] - ) - signed = sign_raw_tx("bob", raw) - txid = send_raw(signed["hex"]) - mine_and_confirm() - ok(f"Created 1000-sat and 546-sat dust outputs to Alice in TX {txid[:16]}…") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 4. Spending Dust with Normal Inputs -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_04(): - header(4, "Spending Dust with Normal Inputs") - ensure_funds("alice", 0.5) - utxos = get_utxos("alice", 1) - dust_utxos = [u for u in utxos if u["amount"] <= 0.00001] - normal_utxos = [u for u in utxos if u["amount"] > 0.001] - - if not dust_utxos: - info("No dust UTXOs, creating one first…") - ensure_funds("bob", 1.0) - a = get_new_address("alice", "bech32") - bu = get_utxos("bob", 1) - big = max(bu, key=lambda u: u["amount"]) - ch = get_new_address("bob", "bech32") - raw = create_raw_tx( - [{"txid": big["txid"], "vout": big["vout"]}], - [{a: 0.00001000}, {ch: round(big["amount"] - 0.00001 - 0.0001, 8)}] - ) - signed = sign_raw_tx("bob", raw) - send_raw(signed["hex"]) - mine_and_confirm() - utxos = get_utxos("alice", 1) - dust_utxos = [u for u in utxos if u["amount"] <= 0.00001] - normal_utxos = [u for u in utxos if u["amount"] > 0.001] - - if not normal_utxos: - ensure_funds("alice", 0.5) - mine_and_confirm() - utxos = get_utxos("alice", 1) - normal_utxos = [u for u in utxos if u["amount"] > 0.001] - - dust = dust_utxos[0] - normal = normal_utxos[0] - dest = get_new_address("bob", "bech32") - total = dust["amount"] + normal["amount"] - raw = create_raw_tx( - [{"txid": dust["txid"], "vout": dust["vout"]}, - {"txid": normal["txid"], "vout": normal["vout"]}], - [{dest: round(total - 0.0001, 8)}] - ) - signed = sign_raw_tx("alice", raw) - txid = send_raw(signed["hex"]) - mine_and_confirm() - ok(f"Spent dust ({int(dust['amount']*1e8)} sats) + normal ({normal['amount']:.8f}) together in TX {txid[:16]}…") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 5. Change Detection -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_05(): - header(5, "Change Detection — Round Payment") - ensure_funds("alice", 1.0) - bob_addr = get_new_address("bob", "bech32") - txid = send_to_address("alice", bob_addr, 0.05) - mine_and_confirm() - ok(f"Alice paid Bob 0.05 BTC (round amount) in TX {txid[:16]}… — change output is obvious") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 6. Consolidation Origin -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_06(): - header(6, "Consolidation Origin") - ensure_funds("bob", 2.0) - for _ in range(4): - addr = get_new_address("alice", "bech32") - send_to_address("bob", addr, 0.003) - mine_and_confirm() - - utxos = get_utxos("alice", 1) - small = [u for u in utxos if 0.002 < u["amount"] < 0.004][:4] - if len(small) < 3: - info(f"Only {len(small)} small UTXOs, creating more…") - for _ in range(4): - addr = get_new_address("alice", "bech32") - send_to_address("bob", addr, 0.003) - mine_and_confirm() - utxos = get_utxos("alice", 1) - small = [u for u in utxos if 0.002 < u["amount"] < 0.004][:4] - - inputs = [{"txid": u["txid"], "vout": u["vout"]} for u in small] - consol_addr = get_new_address("alice", "bech32") - total = sum(u["amount"] for u in small) - raw = create_raw_tx(inputs, [{consol_addr: round(total - 0.0001, 8)}]) - signed = sign_raw_tx("alice", raw) - consol_txid = send_raw(signed["hex"]) - mine_and_confirm() - ok(f"Consolidated {len(small)} UTXOs → 1 in TX {consol_txid[:16]}…") - - # Now spend the consolidated output - utxos = get_utxos("alice", 1) - cu = [u for u in utxos if u["txid"] == consol_txid] - if cu: - dest = get_new_address("carol", "bech32") - raw = create_raw_tx( - [{"txid": cu[0]["txid"], "vout": cu[0]["vout"]}], - [{dest: round(cu[0]["amount"] - 0.0001, 8)}] - ) - signed = sign_raw_tx("alice", raw) - txid2 = send_raw(signed["hex"]) - mine_and_confirm() - ok(f"Spent consolidated UTXO in TX {txid2[:16]}… — carries full cluster history") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 7. Script Type Mixing -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_07(): - header(7, "Script Type Mixing") - ensure_funds("bob", 2.0) - wpkh = get_new_address("alice", "bech32") - tr = get_new_address("alice", "bech32m") - send_to_address("bob", wpkh, 0.005) - send_to_address("bob", tr, 0.005) - mine_and_confirm() - - utxos = get_utxos("alice", 1) - def is_wpkh(addr): - return addr and not addr.startswith(("tb1p","bc1p","bcrt1p")) and addr.startswith(("tb1q","bc1q","bcrt1q")) - def is_tr(addr): - return addr and addr.startswith(("tb1p","bc1p","bcrt1p")) - wu = next((u for u in utxos if is_wpkh(u.get("address","")) and u["amount"] >= 0.004), None) - tu = next((u for u in utxos if is_tr(u.get("address","")) and u["amount"] >= 0.004), None) - if not wu or not tu: - info("Could not find both UTXO types") - return - dest = get_new_address("bob", "bech32") - total = wu["amount"] + tu["amount"] - raw = create_raw_tx( - [{"txid": wu["txid"], "vout": wu["vout"]}, - {"txid": tu["txid"], "vout": tu["vout"]}], - [{dest: round(total - 0.0002, 8)}] - ) - signed = sign_raw_tx("alice", raw) - txid = send_raw(signed["hex"]) - mine_and_confirm() - ok(f"Mixed P2WPKH + P2TR inputs in TX {txid[:16]}… — script type fingerprint") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 8. Cluster Merge -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_08(): - header(8, "Cluster Merge") - ensure_funds("bob", 2.0) - ensure_funds("carol", 2.0) - a_addr = get_new_address("alice", "bech32") - b_addr = get_new_address("alice", "bech32") - txid_a = send_to_address("bob", a_addr, 0.004) - txid_b = send_to_address("carol", b_addr, 0.004) - mine_and_confirm() - - utxos = get_utxos("alice", 1) - ua = next((u for u in utxos if u["txid"] == txid_a), None) - ub = next((u for u in utxos if u["txid"] == txid_b), None) - if not ua: ua = next((u for u in utxos if u.get("address") == a_addr), None) - if not ub: ub = next((u for u in utxos if u.get("address") == b_addr), None) - if not ua or not ub: - info("Could not find both cluster UTXOs") - return - dest = get_new_address("bob", "bech32") - total = ua["amount"] + ub["amount"] - raw = create_raw_tx( - [{"txid": ua["txid"], "vout": ua["vout"]}, - {"txid": ub["txid"], "vout": ub["vout"]}], - [{dest: round(total - 0.0002, 8)}] - ) - signed = sign_raw_tx("alice", raw) - txid = send_raw(signed["hex"]) - mine_and_confirm() - ok(f"Merged Bob-cluster and Carol-cluster UTXOs in TX {txid[:16]}…") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 9. Lookback Depth -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_09(): - header(9, "Lookback Depth / UTXO Age") - old_addr = get_new_address("alice", "bech32") - send_to_address("miner", old_addr, 0.01) - mine_blocks(20) - new_addr = get_new_address("alice", "bech32") - send_to_address("miner", new_addr, 0.01) - mine_and_confirm() - ok(f"Created old UTXO (20+ blocks ago) and new UTXO (just now) for Alice") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 10. Exchange Origin -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_10(): - header(10, "Exchange Origin — Batch Withdrawal") - ensure_funds("exchange", 5.0) - batch = {} - wallets = ["alice", "bob", "carol", "alice", "bob", "carol", "alice", "bob"] - for i in range(8): - addr = get_new_address(wallets[i], "bech32") - batch[addr] = round(0.01 + i * 0.001, 8) - txid = cli("sendmany", "", json.dumps(batch), wallet="exchange") - mine_and_confirm() - ok(f"Exchange batch withdrawal to 8 recipients in TX {txid[:16]}…") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 11. Tainted UTXOs -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_11(): - header(11, "Tainted UTXOs / Dirty Money") - ensure_funds("risky", 2.0) - ensure_funds("bob", 1.0) - ta = get_new_address("alice", "bech32") - taint_txid = send_to_address("risky", ta, 0.01) - ca = get_new_address("alice", "bech32") - clean_txid = send_to_address("bob", ca, 0.01) - mine_and_confirm() - - utxos = get_utxos("alice", 1) - tu = next((u for u in utxos if u["txid"] == taint_txid), None) - cu = next((u for u in utxos if u["txid"] == clean_txid), None) - if not tu: tu = next((u for u in utxos if u.get("address") == ta), None) - if not cu: cu = next((u for u in utxos if u.get("address") == ca), None) - if not tu or not cu: - info("Could not locate tainted + clean UTXOs") - return - dest = get_new_address("carol", "bech32") - total = tu["amount"] + cu["amount"] - raw = create_raw_tx( - [{"txid": tu["txid"], "vout": tu["vout"]}, - {"txid": cu["txid"], "vout": cu["vout"]}], - [{dest: round(total - 0.0002, 8)}] - ) - signed = sign_raw_tx("alice", raw) - txid = send_raw(signed["hex"]) - mine_and_confirm() - ok(f"Merged tainted + clean UTXOs in TX {txid[:16]}… — taint propagation") - -# ═══════════════════════════════════════════════════════════════════════════════ -# 12. Behavioral Fingerprinting -# ═══════════════════════════════════════════════════════════════════════════════ -def reproduce_12(): - header(12, "Behavioral Fingerprinting") - ensure_funds("alice", 3.0) - ensure_funds("bob", 3.0) - - info("Alice's pattern: round amounts, always bech32…") - for i in range(5): - dest = get_new_address("carol", "bech32") - send_to_address("alice", dest, 0.01 * (i + 1)) - - mine_and_confirm() - - info("Bob's pattern: odd amounts, mixed address types…") - for i in range(5): - atype = "bech32m" if i % 2 == 0 else "bech32" - dest = get_new_address("carol", atype) - send_to_address("bob", dest, round(0.00723 * (i + 1) + 0.00011, 8)) - - mine_and_confirm() - ok("Created distinguishable behavioral patterns for Alice and Bob") - - -# ═══════════════════════════════════════════════════════════════════════════════ -# Main -# ═══════════════════════════════════════════════════════════════════════════════ -ALL = [ - (1, "Address Reuse", reproduce_01), - (2, "Multi-input / CIOH", reproduce_02), - (3, "Dust UTXO Detection", reproduce_03), - (4, "Dust Spending w/ Normal", reproduce_04), - (5, "Change Detection", reproduce_05), - (6, "Consolidation Origin", reproduce_06), - (7, "Script Type Mixing", reproduce_07), - (8, "Cluster Merge", reproduce_08), - (9, "Lookback Depth", reproduce_09), - (10, "Exchange Origin", reproduce_10), - (11, "Tainted UTXOs", reproduce_11), - (12, "Behavioral Fingerprint", reproduce_12), -] - -def main(): - filt = None - if "-k" in sys.argv: - idx = sys.argv.index("-k") - if idx + 1 < len(sys.argv): - filt = sys.argv[idx + 1] - - print(f"\n{B}{'═'*78}{R}") - print(f"{B}{C} REPRODUCE — Bitcoin Privacy Vulnerabilities{R}") - print(f"{B}{C} Custom Signet — {get_block_count()} blocks{R}") - print(f"{B}{'═'*78}{R}") - - for num, name, fn in ALL: - if filt and str(num) != filt: - continue - try: - fn() - except Exception as e: - print(f" \033[91m✗ ERROR in {name}: {e}\033[0m") - import traceback; traceback.print_exc() - - print(f"\n{B}{'═'*78}{R}") - print(f" {G}Done. All vulnerability scenarios have been created on-chain.{R}") - print(f" Now run: python3 detect.py ") - print(f"{B}{'═'*78}{R}\n") - -if __name__ == "__main__": - main() diff --git a/backend/script/setup.sh b/backend/script/setup.sh deleted file mode 100755 index c33e632..0000000 --- a/backend/script/setup.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env bash -# ============================================================================= -# setup.sh — Bootstrap Bitcoin Core regtest for privacy vulnerability testing -# ============================================================================= -# Reproduces the full environment: -# • Stops any running bitcoind (both regtest and signet) -# • Optionally wipes the regtest data dir (pass --fresh to start from block 0) -# • Starts bitcoind with all config passed via CLI flags (no bitcoin.conf edits) -# • Creates wallets: miner alice bob carol exchange risky -# • Mines 110 blocks so coinbases mature and miner has spendable BTC -# -# Usage: -# ./setup.sh # keep existing chain state, reload wallets -# ./setup.sh --fresh # wipe regtest, start from genesis -# ============================================================================= -set -euo pipefail - -# ─── Config ─────────────────────────────────────────────────────────────────── -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -DATADIR="${SCRIPT_DIR}/bitcoin-data" -REGTEST_DIR="${DATADIR}/regtest" -WALLETS=(miner alice bob carol exchange risky) -INITIAL_BLOCKS=110 # must be >100 so coinbases mature - -# ─── Helpers ────────────────────────────────────────────────────────────────── -G="\033[92m"; Y="\033[93m"; R="\033[91m"; B="\033[1m"; C="\033[96m"; RST="\033[0m" -ok() { echo -e " ${G}✓${RST} $*"; } -info() { echo -e " ${Y}ℹ${RST} $*"; } -err() { echo -e " ${R}✗${RST} $*"; exit 1; } -bcli() { bitcoin-cli -datadir="$DATADIR" -regtest "$@"; } - -# ─── Parse args ─────────────────────────────────────────────────────────────── -FRESH=0 -for arg in "$@"; do - [[ "$arg" == "--fresh" ]] && FRESH=1 -done - -echo "" -echo -e "${B}${C}══════════════════════════════════════════════════════════${RST}" -echo -e "${B}${C} Bitcoin Regtest Setup — privacy vulnerability harness${RST}" -echo -e "${B}${C}══════════════════════════════════════════════════════════${RST}" -[[ $FRESH -eq 1 ]] && echo -e " ${Y}Mode: FRESH — regtest chain will be wiped${RST}" - -# ─── 1. Stop running daemons ────────────────────────────────────────────────── -echo "" -echo -e "${B}Step 1: Stop any running bitcoind${RST}" - -# Try to stop regtest instance (port 18443) -if bcli stop 2>/dev/null; then - ok "Stopped regtest bitcoind" - sleep 2 -else - info "No regtest bitcoind running (or already stopped)" -fi - -# Hard-kill any remaining bitcoind processes -if pgrep -x bitcoind > /dev/null 2>&1; then - info "Hard-killing remaining bitcoind processes …" - pkill -x bitcoind || true - sleep 2 -fi - -# ─── 2. Optionally wipe regtest chain ──────────────────────────────────────── -if [[ $FRESH -eq 1 ]]; then - echo "" - echo -e "${B}Step 2: Wipe regtest data dir${RST}" - rm -rf "$REGTEST_DIR" - ok "Wiped ${REGTEST_DIR}" -else - echo "" - info "Step 2: Keeping existing regtest chain (use --fresh to wipe)" -fi - -# ─── 3. Start bitcoind ──────────────────────────────────────────────────────── -echo "" -echo -e "${B}Step 3: Start bitcoind${RST}" -mkdir -p "$DATADIR" -bitcoind -daemon \ - -datadir="$DATADIR" \ - -regtest \ - -txindex=1 \ - -server=1 \ - -fallbackfee=0.00010 \ - -dustrelayfee=0.00000001 \ - -acceptnonstdtxn=1 -ok "bitcoind launched" - -# Wait for RPC to become ready -echo -n " … waiting for RPC" -for i in $(seq 1 30); do - sleep 1 - echo -n "." - if bcli getblockchaininfo > /dev/null 2>&1; then - echo "" - ok "RPC ready after ${i}s" - break - fi - if [[ $i -eq 30 ]]; then - echo "" - err "bitcoind did not respond within 30s — check logs at ${REGTEST_DIR}/debug.log" - fi -done - -BLOCKS=$(bcli getblockcount) -info "Chain height: ${BLOCKS} blocks" - -# ─── 4. Create / load wallets ───────────────────────────────────────────────── -echo "" -echo -e "${B}Step 4: Create wallets${RST}" -for w in "${WALLETS[@]}"; do - if bcli createwallet "$w" 2>/dev/null | grep -q '"name"'; then - ok "Created wallet: ${w}" - else - # Wallet DB already exists on disk — just load it - if bcli loadwallet "$w" 2>/dev/null | grep -q '"name"'; then - ok "Loaded existing wallet: ${w}" - else - # Already loaded (returned error -35) - info "Wallet already loaded: ${w}" - fi - fi -done - -# ─── 5. Mine initial blocks (only if fresh or chain has <110 blocks) ────────── -echo "" -echo -e "${B}Step 5: Mine initial blocks${RST}" -BLOCKS=$(bcli getblockcount) - -if [[ $BLOCKS -lt $INITIAL_BLOCKS ]]; then - NEED=$(( INITIAL_BLOCKS - BLOCKS )) - info "At block ${BLOCKS}, need ${NEED} more to reach ${INITIAL_BLOCKS}" - MINER_ADDR=$(bcli -rpcwallet=miner getnewaddress "" bech32) - bcli generatetoaddress "$NEED" "$MINER_ADDR" > /dev/null - BLOCKS=$(bcli getblockcount) - ok "Mined to block ${BLOCKS}" -else - ok "Already at block ${BLOCKS} — no mining needed" -fi - -MINER_BAL=$(bcli -rpcwallet=miner getbalance) -ok "Miner balance: ${MINER_BAL} BTC" - -# ─── 6. Summary ─────────────────────────────────────────────────────────────── -echo "" -echo -e "${B}${C}══════════════════════════════════════════════════════════${RST}" -echo -e "${B} Setup complete!${RST}" -echo -e "${B}${C}══════════════════════════════════════════════════════════${RST}" -echo -e " Chain: ${G}regtest${RST}" -echo -e " Blocks: ${G}$(bcli getblockcount)${RST}" -echo -e " Wallets: ${G}${WALLETS[*]}${RST}" -echo "" -echo -e " Next steps:" -echo -e " python3 reproduce.py # create 12 vulnerability scenarios" -echo -e " python3 detect.py --wallet alice \\" -echo -e " --known-risky-wallets risky \\" -echo -e " --known-exchange-wallets exchange" -echo "" diff --git a/backend/src/StealthBackend/.dockerignore b/backend/src/StealthBackend/.dockerignore deleted file mode 100644 index 94810d0..0000000 --- a/backend/src/StealthBackend/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -* -!target/*-runner -!target/*-runner.jar -!target/lib/* -!target/quarkus-app/* \ No newline at end of file diff --git a/backend/src/StealthBackend/.gitignore b/backend/src/StealthBackend/.gitignore deleted file mode 100644 index 91a800a..0000000 --- a/backend/src/StealthBackend/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -#Maven -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -release.properties -.flattened-pom.xml - -# Eclipse -.project -.classpath -.settings/ -bin/ - -# IntelliJ -.idea -*.ipr -*.iml -*.iws - -# NetBeans -nb-configuration.xml - -# Visual Studio Code -.vscode -.factorypath - -# OSX -.DS_Store - -# Vim -*.swp -*.swo - -# patch -*.orig -*.rej - -# Local environment -.env - -# Plugin directory -/.quarkus/cli/plugins/ -# TLS Certificates -.certs/ diff --git a/backend/src/StealthBackend/.mvn/wrapper/maven-wrapper.properties b/backend/src/StealthBackend/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 533e775..0000000 --- a/backend/src/StealthBackend/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,4 +0,0 @@ -wrapperVersion=3.3.4 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip -distributionSha256Sum=305773a68d6ddfd413df58c82b3f8050e89778e777f3a745c8e5b8cbea4018ef diff --git a/backend/src/StealthBackend/BITCOIN_BACKEND.md b/backend/src/StealthBackend/BITCOIN_BACKEND.md deleted file mode 100644 index e69de29..0000000 diff --git a/backend/src/StealthBackend/README.md b/backend/src/StealthBackend/README.md deleted file mode 100644 index 5cfdf7d..0000000 --- a/backend/src/StealthBackend/README.md +++ /dev/null @@ -1,115 +0,0 @@ -# stealthbackend - -This project uses Quarkus, the Supersonic Subatomic Java Framework. - -If you want to learn more about Quarkus, please visit its website: . - -## Stealth-specific notes - -### Scan endpoint - -The frontend calls: - -```http -GET /api/wallet/scan?descriptor= -``` - -This endpoint executes the Python detector configured by `stealth.detect.script` (default: `../../script/detect.py`) and returns its JSON report verbatim. - -### Detector type taxonomy - -`detect.py` can emit the following finding `type` values: - -- `ADDRESS_REUSE` -- `CIOH` -- `DUST` -- `DUST_SPENDING` -- `CHANGE_DETECTION` -- `CONSOLIDATION` -- `SCRIPT_TYPE_MIXING` -- `CLUSTER_MERGE` -- `UTXO_AGE_SPREAD` -- `EXCHANGE_ORIGIN` -- `TAINTED_UTXO_MERGE` -- `BEHAVIORAL_FINGERPRINT` - -Warning-only types: - -- `DORMANT_UTXOS` -- `DIRECT_TAINT` - -Severity values are uppercase strings (for example: `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`). - -## Running the application in dev mode - -You can run your application in dev mode that enables live coding using: - -```shell script -./mvnw quarkus:dev -``` - -> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at . - -## Packaging and running the application - -The application can be packaged using: - -```shell script -./mvnw package -``` - -It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory. -Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory. - -The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`. - -If you want to build an _über-jar_, execute the following command: - -```shell script -./mvnw package -Dquarkus.package.jar.type=uber-jar -``` - -The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`. - -## Creating a native executable - -You can create a native executable using: - -```shell script -./mvnw package -Dnative -``` - -Or, if you don't have GraalVM installed, you can run the native executable build in a container using: - -```shell script -./mvnw package -Dnative -Dquarkus.native.container-build=true -``` - -You can then execute your native executable with: `./target/stealthbackend-1.0-SNAPSHOT-runner` - -If you want to learn more about building native executables, please consult . - -## Related Guides - -- REST ([guide](https://quarkus.io/guides/rest)): A Jakarta REST implementation utilizing build time processing and - Vert.x. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on - it. -- REST Client ([guide](https://quarkus.io/guides/rest-client)): Call REST services -- SmallRye OpenAPI ([guide](https://quarkus.io/guides/openapi-swaggerui)): Document your REST APIs with OpenAPI - comes - with Swagger UI -- REST Jackson ([guide](https://quarkus.io/guides/rest#json-serialisation)): Jackson serialization support for Quarkus - REST. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it - -## Provided Code - -### REST Client - -Invoke different services through REST with JSON - -[Related guide section...](https://quarkus.io/guides/rest-client) - -### REST - -Easily start your REST Web Services - -[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources) diff --git a/backend/src/StealthBackend/TESTNET4_CONNECTION.md b/backend/src/StealthBackend/TESTNET4_CONNECTION.md deleted file mode 100644 index 413fc2e..0000000 --- a/backend/src/StealthBackend/TESTNET4_CONNECTION.md +++ /dev/null @@ -1,231 +0,0 @@ -# Conexão com Bitcoin Testnet4 - -Este guia mostra como conectar na blockchain Bitcoin testnet4 usando BDK-JVM. - -## 🚀 Como Funciona - -### 1. Executar o Exemplo de Conexão - -#### Opção A: Via Código Java -Execute a classe `BitcoinConnectionExample`: - -```bash -cd /home/herbe/src/stealth/backend/src/StealthBackend -mvn compile -mvn exec:java -Dexec.mainClass="org.backend.stealth.service.BitcoinConnectionExample" -``` - -#### Opção B: Via REST API -Inicie o servidor Quarkus: - -```bash -./mvnw quarkus:dev -``` - -Acesse os endpoints: - -**1. Conectar na blockchain testnet4:** -```bash -curl -X POST http://localhost:8080/api/testnet4/connect -``` - -**2. Obter informações da blockchain:** -```bash -curl http://localhost:8080/api/testnet4/info -``` - -**3. Gerar novo endereço:** -```bash -curl http://localhost:8080/api/testnet4/address -``` - -**4. Verificar saldo:** -```bash -curl http://localhost:8080/api/testnet4/balance -``` - -**5. Sincronizar wallet:** -```bash -curl -X POST http://localhost:8080/api/testnet4/sync -``` - -## 📊 O Que o Código Faz - -### 1. Configuração da Network -```java -Network network = Network.TESTNET; -``` -Define que vamos usar a testnet do Bitcoin. - -### 2. Configuração do Esplora -```java -String esploraUrl = "https://mempool.space/testnet4/api"; -EsploraConfig esploraConfig = new EsploraConfig( - esploraUrl, // URL do servidor Esplora - null, // Proxy (null = sem proxy) - 5L, // Timeout em segundos - null, // Stop gap - null // Timeout para requests longos -); -``` -Esplora é uma API que permite acessar dados da blockchain sem rodar um nó completo. - -### 3. Conexão com Blockchain -```java -BlockchainConfig blockchainConfig = BlockchainConfig.esplora(esploraConfig); -Blockchain blockchain = new Blockchain(blockchainConfig); -``` -Cria a conexão com a blockchain testnet4. - -### 4. Verificar Conexão -```java -long height = blockchain.getHeight(); -String blockHash = blockchain.getBlockHash(height); -``` -Obtém a altura atual (número de blocos) e o hash do último bloco. - -### 5. Criar Wallet -```java -Mnemonic mnemonic = new Mnemonic(WordCount.WORDS12); -DescriptorSecretKey descriptorSecretKey = new DescriptorSecretKey(network, mnemonic, null); - -String descriptor = "wpkh(" + descriptorSecretKey.asString() + "/84'/1'/0'/0/*)"; -String changeDescriptor = "wpkh(" + descriptorSecretKey.asString() + "/84'/1'/0'/1/*)"; - -Wallet wallet = new Wallet(descriptor, changeDescriptor, network, databaseConfig); -``` -Cria uma wallet HD (Hierarchical Deterministic) usando BIP84 (native segwit). - -### 6. Sincronizar Wallet -```java -wallet.sync(blockchain, null); -``` -Sincroniza a wallet com a blockchain para obter transações e saldo. - -### 7. Gerar Endereço -```java -AddressInfo addressInfo = wallet.getAddress(AddressIndex.NEW); -``` -Gera um novo endereço para receber bitcoins. - -## 🔑 Componentes Principais - -### Blockchain -- Representa a conexão com a rede Bitcoin -- Permite consultar blocos, altura, e broadcast de transações - -### Wallet -- Gerencia chaves privadas e endereços -- Rastreia saldo e transações -- Cria e assina transações - -### Mnemonic -- 12 palavras que permitem recuperar a wallet -- **MUITO IMPORTANTE**: Guarde com segurança! -- Qualquer pessoa com essas palavras tem acesso aos fundos - -### Descriptor -- Define a estrutura da wallet -- `wpkh` = Witness Public Key Hash (native segwit) -- `/84'/1'/0'/0/*` = Caminho BIP84 para testnet - -## 💰 Como Obter Testnet4 Bitcoins - -1. Execute o código para gerar um endereço -2. Copie o endereço gerado (começa com `tb1...`) -3. Acesse um faucet de testnet4: - - https://mempool.space/testnet4 - - Procure por "faucet" na página -4. Cole seu endereço e solicite bitcoins -5. Aguarde alguns minutos para confirmação -6. Sincronize a wallet e verifique o saldo - -## 🔧 Estrutura do Código - -``` -src/main/java/org/backend/stealth/ -├── service/ -│ ├── BitcoinController.java # Controller principal com lógica de conexão -│ └── BitcoinConnectionExample.java # Exemplo standalone -├── controller/ -│ └── BitcoinTestnet4Resource.java # REST API endpoints -└── service/dto/ - ├── BlockchainInfoDTO.java # DTO para info da blockchain - ├── AddressResponseDTO.java # DTO para endereços - ├── BalanceDTO.java # DTO para saldo - ├── ErrorDTO.java # DTO para erros - └── MessageDTO.java # DTO para mensagens -``` - -## 📝 Exemplo de Resposta - -### GET /api/testnet4/info -```json -{ - "network": "TESTNET4", - "height": 150234, - "latestBlockHash": "00000000000000123abc...", - "esploraUrl": "https://mempool.space/testnet4/api" -} -``` - -### GET /api/testnet4/address -```json -{ - "address": "tb1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh", - "instructions": "Use um faucet para receber testnet4 bitcoins: https://mempool.space/testnet4" -} -``` - -### GET /api/testnet4/balance -```json -{ - "total": 100000, - "confirmed": 100000, - "immature": 0, - "trustedPending": 0, - "untrustedPending": 0 -} -``` - -## ⚠️ Notas Importantes - -1. **Testnet4**: Esta é uma rede de testes. Os bitcoins não têm valor real. -2. **Mnemonic**: Sempre guarde as 12 palavras em local seguro. -3. **Esplora**: Dependemos de um servidor externo. Se estiver lento, pode ser problema na API. -4. **Sincronização**: A primeira sincronização pode demorar alguns segundos. - -## 🐛 Troubleshooting - -### Erro: "Connection timeout" -- Verifique sua conexão com internet -- Tente usar outro servidor Esplora -- Aumente o timeout na configuração - -### Erro: "Invalid descriptor" -- Verifique se está usando Network.TESTNET -- Confirme que o descriptor está correto - -### Saldo sempre zero -- Aguarde a confirmação da transação (10-60 minutos) -- Sincronize a wallet novamente -- Verifique se usou o endereço correto no faucet - -## 📚 Recursos Adicionais - -- [BDK Documentation](https://bitcoindevkit.org/) -- [Mempool.space Testnet4](https://mempool.space/testnet4) -- [BIP84 Specification](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki) -- [Bitcoin Testnet Guide](https://developer.bitcoin.org/examples/testing.html) - -## ✅ Checklist de Teste - -- [ ] Executar `BitcoinConnectionExample` -- [ ] Ver log de conexão bem-sucedida -- [ ] Verificar altura da blockchain -- [ ] Salvar as 12 palavras do mnemonic -- [ ] Copiar endereço gerado -- [ ] Solicitar bitcoins no faucet -- [ ] Sincronizar wallet -- [ ] Verificar saldo atualizado - diff --git a/backend/src/StealthBackend/mvnw b/backend/src/StealthBackend/mvnw deleted file mode 100755 index bd8896b..0000000 --- a/backend/src/StealthBackend/mvnw +++ /dev/null @@ -1,295 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.4 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - if [ -n "${JAVA_HOME-}" ]; then - if [ -x "$JAVA_HOME/jre/sh/java" ]; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -scriptDir="$(dirname "$0")" -scriptName="$(basename "$0")" - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi - -# Find the actual extracted directory name (handles snapshots where filename != directory name) -actualDistributionDir="" - -# First try the expected directory name (for regular distributions) -if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then - if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then - actualDistributionDir="$distributionUrlNameMain" - fi -fi - -# If not found, search for any directory with the Maven executable (for snapshots) -if [ -z "$actualDistributionDir" ]; then - # enable globbing to iterate over items - set +f - for dir in "$TMP_DOWNLOAD_DIR"/*; do - if [ -d "$dir" ]; then - if [ -f "$dir/bin/$MVN_CMD" ]; then - actualDistributionDir="$(basename "$dir")" - break - fi - fi - done - set -f -fi - -if [ -z "$actualDistributionDir" ]; then - verbose "Contents of $TMP_DOWNLOAD_DIR:" - verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" - die "Could not find Maven distribution directory in extracted archive" -fi - -verbose "Found extracted Maven distribution directory: $actualDistributionDir" -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/backend/src/StealthBackend/mvnw.cmd b/backend/src/StealthBackend/mvnw.cmd deleted file mode 100644 index 5761d94..0000000 --- a/backend/src/StealthBackend/mvnw.cmd +++ /dev/null @@ -1,189 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.4 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' - -$MAVEN_M2_PATH = "$HOME/.m2" -if ($env:MAVEN_USER_HOME) { - $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" -} - -if (-not (Test-Path -Path $MAVEN_M2_PATH)) { - New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null -} - -$MAVEN_WRAPPER_DISTS = $null -if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { - $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" -} else { - $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" -} - -$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" -$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null - -# Find the actual extracted directory name (handles snapshots where filename != directory name) -$actualDistributionDir = "" - -# First try the expected directory name (for regular distributions) -$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" -$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" -if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { - $actualDistributionDir = $distributionUrlNameMain -} - -# If not found, search for any directory with the Maven executable (for snapshots) -if (!$actualDistributionDir) { - Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { - $testPath = Join-Path $_.FullName "bin/$MVN_CMD" - if (Test-Path -Path $testPath -PathType Leaf) { - $actualDistributionDir = $_.Name - } - } -} - -if (!$actualDistributionDir) { - Write-Error "Could not find Maven distribution directory in extracted archive" -} - -Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/backend/src/StealthBackend/pom.xml b/backend/src/StealthBackend/pom.xml deleted file mode 100644 index c341d50..0000000 --- a/backend/src/StealthBackend/pom.xml +++ /dev/null @@ -1,140 +0,0 @@ - - - 4.0.0 - org.backend.stealt - stealthbackend - 1.0-SNAPSHOT - quarkus - - - 3.15.0 - 21 - UTF-8 - UTF-8 - quarkus-bom - io.quarkus.platform - 3.32.1 - true - 3.5.4 - - - - - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - - - - - - - io.quarkus - quarkus-rest - - - io.quarkus - quarkus-rest-client-jackson - - - io.quarkus - quarkus-rest-client - - - io.quarkus - quarkus-smallrye-openapi - - - io.quarkus - quarkus-rest-jackson - - - io.quarkus - quarkus-arc - - - io.quarkus - quarkus-junit - test - - - io.rest-assured - rest-assured - test - - - org.slf4j - slf4j-api - - - - - - - ${quarkus.platform.group-id} - quarkus-maven-plugin - ${quarkus.platform.version} - true - - - maven-compiler-plugin - ${compiler-plugin.version} - - true - - - - maven-surefire-plugin - ${surefire-plugin.version} - - @{argLine} - - org.jboss.logmanager.LogManager - ${maven.home} - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - - @{argLine} - - ${project.build.directory}/${project.build.finalName}-runner - - org.jboss.logmanager.LogManager - ${maven.home} - - - - - - - - - native - - - native - - - - false - false - true - - - - diff --git a/backend/src/StealthBackend/src/main/docker/Dockerfile.jvm b/backend/src/StealthBackend/src/main/docker/Dockerfile.jvm deleted file mode 100644 index 1affb13..0000000 --- a/backend/src/StealthBackend/src/main/docker/Dockerfile.jvm +++ /dev/null @@ -1,100 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode -# -# Before building the container image run: -# -# ./mvnw package -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/stealthbackend-jvm . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/stealthbackend-jvm -# -# If you want to include the debug port into your docker image -# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. -# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 -# when running the container -# -# Then run the container using : -# -# docker run -i --rm -p 8080:8080 quarkus/stealthbackend-jvm -# -# This image uses the `run-java.sh` script to run the application. -# This scripts computes the command line to execute your Java application, and -# includes memory/GC tuning. -# You can configure the behavior using the following environment properties: -# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") - Be aware that this will override -# the default JVM options, use `JAVA_OPTS_APPEND` to append options -# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options -# in JAVA_OPTS (example: "-Dsome.property=foo") -# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is -# used to calculate a default maximal heap memory based on a containers restriction. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio -# of the container available memory as set here. The default is `50` which means 50% -# of the available memory is used as an upper boundary. You can skip this mechanism by -# setting this value to `0` in which case no `-Xmx` option is added. -# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This -# is used to calculate a default initial heap memory based on the maximum heap memory. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio -# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` -# is used as the initial heap size. You can skip this mechanism by setting this value -# to `0` in which case no `-Xms` option is added (example: "25") -# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. -# This is used to calculate the maximum value of the initial heap memory. If used in -# a container without any memory constraints for the container then this option has -# no effect. If there is a memory constraint then `-Xms` is limited to the value set -# here. The default is 4096MB which means the calculated value of `-Xms` never will -# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") -# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output -# when things are happening. This option, if set to true, will set -# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). -# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: -# true"). -# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). -# - CONTAINER_CORE_LIMIT: A calculated core limit as described in -# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") -# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). -# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. -# (example: "20") -# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. -# (example: "40") -# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. -# (example: "4") -# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus -# previous GC times. (example: "90") -# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") -# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") -# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should -# contain the necessary JRE command-line options to specify the required GC, which -# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). -# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") -# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") -# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be -# accessed directly. (example: "foo.example.com,bar.example.com") -# -# You can find more information about the UBI base runtime images and their configuration here: -# https://rh-openjdk.github.io/redhat-openjdk-containers/ -### -FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.24 - -ENV LANGUAGE='en_US:en' - - -# We make four distinct layers so if there are application changes the library layers can be re-used -COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/ -COPY --chown=185 target/quarkus-app/*.jar /deployments/ -COPY --chown=185 target/quarkus-app/app/ /deployments/app/ -COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ - -EXPOSE 8080 -USER 185 -ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" -ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" - -ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ] - diff --git a/backend/src/StealthBackend/src/main/docker/Dockerfile.legacy-jar b/backend/src/StealthBackend/src/main/docker/Dockerfile.legacy-jar deleted file mode 100644 index 9ce402b..0000000 --- a/backend/src/StealthBackend/src/main/docker/Dockerfile.legacy-jar +++ /dev/null @@ -1,96 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode -# -# Before building the container image run: -# -# ./mvnw package -Dquarkus.package.jar.type=legacy-jar -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/stealthbackend-legacy-jar . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/stealthbackend-legacy-jar -# -# If you want to include the debug port into your docker image -# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. -# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 -# when running the container -# -# Then run the container using : -# -# docker run -i --rm -p 8080:8080 quarkus/stealthbackend-legacy-jar -# -# This image uses the `run-java.sh` script to run the application. -# This scripts computes the command line to execute your Java application, and -# includes memory/GC tuning. -# You can configure the behavior using the following environment properties: -# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") - Be aware that this will override -# the default JVM options, use `JAVA_OPTS_APPEND` to append options -# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options -# in JAVA_OPTS (example: "-Dsome.property=foo") -# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is -# used to calculate a default maximal heap memory based on a containers restriction. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio -# of the container available memory as set here. The default is `50` which means 50% -# of the available memory is used as an upper boundary. You can skip this mechanism by -# setting this value to `0` in which case no `-Xmx` option is added. -# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This -# is used to calculate a default initial heap memory based on the maximum heap memory. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio -# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` -# is used as the initial heap size. You can skip this mechanism by setting this value -# to `0` in which case no `-Xms` option is added (example: "25") -# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. -# This is used to calculate the maximum value of the initial heap memory. If used in -# a container without any memory constraints for the container then this option has -# no effect. If there is a memory constraint then `-Xms` is limited to the value set -# here. The default is 4096MB which means the calculated value of `-Xms` never will -# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") -# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output -# when things are happening. This option, if set to true, will set -# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). -# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: -# true"). -# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). -# - CONTAINER_CORE_LIMIT: A calculated core limit as described in -# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") -# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). -# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. -# (example: "20") -# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. -# (example: "40") -# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. -# (example: "4") -# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus -# previous GC times. (example: "90") -# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") -# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") -# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should -# contain the necessary JRE command-line options to specify the required GC, which -# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). -# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") -# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") -# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be -# accessed directly. (example: "foo.example.com,bar.example.com") -# -# You can find more information about the UBI base runtime images and their configuration here: -# https://rh-openjdk.github.io/redhat-openjdk-containers/ -### -FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.24 - -ENV LANGUAGE='en_US:en' - - -COPY target/lib/* /deployments/lib/ -COPY target/*-runner.jar /deployments/quarkus-run.jar - -EXPOSE 8080 -USER 185 -ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" -ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" - -ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ] diff --git a/backend/src/StealthBackend/src/main/docker/Dockerfile.native b/backend/src/StealthBackend/src/main/docker/Dockerfile.native deleted file mode 100644 index 18f483a..0000000 --- a/backend/src/StealthBackend/src/main/docker/Dockerfile.native +++ /dev/null @@ -1,29 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. -# -# Before building the container image run: -# -# ./mvnw package -Dnative -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.native -t quarkus/stealthbackend . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/stealthbackend -# -# The ` registry.access.redhat.com/ubi9/ubi-minimal:9.7` base image is based on UBI 9. -# To use UBI 8, switch to `quay.io/ubi8/ubi-minimal:8.10`. -### -FROM registry.access.redhat.com/ubi9/ubi-minimal:9.7 -WORKDIR /work/ -RUN chown 1001 /work \ - && chmod "g+rwX" /work \ - && chown 1001:root /work -COPY --chown=1001:root --chmod=0755 target/*-runner /work/application - -EXPOSE 8080 -USER 1001 - -ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/backend/src/StealthBackend/src/main/docker/Dockerfile.native-micro b/backend/src/StealthBackend/src/main/docker/Dockerfile.native-micro deleted file mode 100644 index 0921f25..0000000 --- a/backend/src/StealthBackend/src/main/docker/Dockerfile.native-micro +++ /dev/null @@ -1,32 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. -# It uses a micro base image, tuned for Quarkus native executables. -# It reduces the size of the resulting container image. -# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image. -# -# Before building the container image run: -# -# ./mvnw package -Dnative -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/stealthbackend . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/stealthbackend -# -# The `quay.io/quarkus/ubi9-quarkus-micro-image:2.0` base image is based on UBI 9. -# To use UBI 8, switch to `quay.io/quarkus/quarkus-micro-image:2.0`. -### -FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0 -WORKDIR /work/ -RUN chown 1001 /work \ - && chmod "g+rwX" /work \ - && chown 1001:root /work -COPY --chown=1001:root --chmod=0755 target/*-runner /work/application - -EXPOSE 8080 -USER 1001 - -ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/backend/src/StealthBackend/src/main/java/org/backend/stealth/controller/WalletResource.java b/backend/src/StealthBackend/src/main/java/org/backend/stealth/controller/WalletResource.java deleted file mode 100644 index 551d7ec..0000000 --- a/backend/src/StealthBackend/src/main/java/org/backend/stealth/controller/WalletResource.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.backend.stealth.controller; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -import java.util.Map; - -@ApplicationScoped -@Path("/api/wallet") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class WalletResource { - - @ConfigProperty(name = "stealth.detect.script", defaultValue = "../../script/detect.py") - String detectScript; - - @GET - @Path("/scan") - public Response scan(@QueryParam("descriptor") String descriptor) { - if (descriptor == null || descriptor.isBlank()) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(Map.of("error", "descriptor query parameter is required")) - .build(); - } - try { - ProcessBuilder pb = new ProcessBuilder("python3", detectScript, descriptor); - pb.redirectErrorStream(false); - Process process = pb.start(); - - String output = new String(process.getInputStream().readAllBytes()); - int exitCode = process.waitFor(); - - if (exitCode != 0 || output.isBlank()) { - String stderr = new String(process.getErrorStream().readAllBytes()); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", stderr.isBlank() ? "detect.py produced no output" : stderr.strip())) - .build(); - } - - return Response.ok(output).type(MediaType.APPLICATION_JSON).build(); - } catch (Exception e) { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(Map.of("error", e.getMessage())) - .build(); - } - } -} diff --git a/backend/src/StealthBackend/src/main/resources/application.properties b/backend/src/StealthBackend/src/main/resources/application.properties deleted file mode 100644 index dc4d1c4..0000000 --- a/backend/src/StealthBackend/src/main/resources/application.properties +++ /dev/null @@ -1,7 +0,0 @@ -quarkus.http.port=8080 -quarkus.http.cors=true -quarkus.http.cors.origins=http://localhost:5173 -quarkus.http.cors.methods=GET,POST,OPTIONS -quarkus.http.cors.headers=Content-Type,Accept - -stealth.detect.script=../../script/detect.py diff --git a/slides/README.md b/slides/README.md deleted file mode 100644 index feab1ab..0000000 --- a/slides/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Stealth Pitch Slides - -Slidev presentation for the Stealth hackathon pitch. - -## Run - -```bash -pnpm install -pnpm run dev -``` - -Opens at http://localhost:3030/ - -## Export - -```bash -pnpm run build # Static SPA to dist/ -pnpm run export # PDF export -``` diff --git "a/slides/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth.pdf" "b/slides/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth.pdf" deleted file mode 100644 index 33fd097..0000000 Binary files "a/slides/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth.pdf" and /dev/null differ diff --git a/slides/package.json b/slides/package.json deleted file mode 100644 index 0833be3..0000000 --- a/slides/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "stealth-pitch", - "private": true, - "type": "module", - "scripts": { - "dev": "pnpm exec slidev slides.md --open", - "build": "pnpm exec slidev build slides.md", - "export": "pnpm exec slidev export slides.md" - }, - "dependencies": { - "@slidev/cli": "^52.0.0", - "@slidev/theme-default": "^0.25.0" - }, - "devDependencies": { - "playwright-chromium": "^1.58.2" - } -} diff --git a/slides/pic-full-260227-1349-18.png b/slides/pic-full-260227-1349-18.png deleted file mode 100644 index 3d49bef..0000000 Binary files a/slides/pic-full-260227-1349-18.png and /dev/null differ diff --git a/slides/pic-full-260227-1349-21.png b/slides/pic-full-260227-1349-21.png deleted file mode 100644 index 647ced2..0000000 Binary files a/slides/pic-full-260227-1349-21.png and /dev/null differ diff --git a/slides/pic-selected-260227-1348-44.png b/slides/pic-selected-260227-1348-44.png deleted file mode 100644 index 1288ba2..0000000 Binary files a/slides/pic-selected-260227-1348-44.png and /dev/null differ diff --git a/slides/pnpm-lock.yaml b/slides/pnpm-lock.yaml deleted file mode 100644 index 58fb7bd..0000000 --- a/slides/pnpm-lock.yaml +++ /dev/null @@ -1,5714 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@slidev/cli': - specifier: ^52.0.0 - version: 52.13.0(@nuxt/kit@3.21.1)(@types/markdown-it@14.1.2)(@types/node@22.19.13)(@vue/compiler-sfc@3.5.29)(markdown-it@14.1.1)(playwright-chromium@1.58.2)(postcss@8.5.6) - '@slidev/theme-default': - specifier: ^0.25.0 - version: 0.25.0 - devDependencies: - playwright-chromium: - specifier: ^1.58.2 - version: 1.58.2 - -packages: - - '@antfu/install-pkg@1.1.0': - resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} - - '@antfu/ni@28.2.0': - resolution: {integrity: sha512-+pnatqUMTpi1g/VxbaTsX9UxibTp5oWCMbfUAQPV91UL9lTIMmlU2uvG8bDETDJ0kJdsZT8zLBctKLJOeL5jmg==} - engines: {node: '>=20'} - hasBin: true - - '@antfu/utils@9.3.0': - resolution: {integrity: sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==} - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-create-class-features-plugin@7.28.6': - resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-member-expression-to-functions@7.28.5': - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - - '@babel/helper-replace-supers@7.28.6': - resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.27.7': - resolution: {integrity: sha512-qnzXzDXdr/po3bOTbTIQZ7+TxNKxpkN5IifVLXS+r7qwynkZfPyjZfE7hCXbo7IoO9TNcSyibgONsf2HauUd3Q==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-syntax-jsx@7.28.6': - resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-typescript@7.28.6': - resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typescript@7.28.6': - resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.27.7': - resolution: {integrity: sha512-X6ZlfR/O/s5EQ/SnUSLzr+6kGnkg8HXGMzpgsMsrJVcfDtH1vIp6ctCN4eZ1LS5c0+te5Cb6Y514fASjMRJ1nw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@braintree/sanitize-url@7.1.2': - resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} - - '@chevrotain/cst-dts-gen@11.1.1': - resolution: {integrity: sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==} - - '@chevrotain/gast@11.1.1': - resolution: {integrity: sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==} - - '@chevrotain/regexp-to-ast@11.1.1': - resolution: {integrity: sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==} - - '@chevrotain/types@11.1.1': - resolution: {integrity: sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==} - - '@chevrotain/utils@11.1.1': - resolution: {integrity: sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==} - - '@drauu/core@1.0.0': - resolution: {integrity: sha512-r1fPyuKaGuNHc8vxRFUT8LxqWjJ3nx+U+zsHcEOurmJoB7uN+zpFw5kTLInfdfvQZ+qF/ebQjw1AwbGcc1XKsQ==} - - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@floating-ui/core@1.7.4': - resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} - - '@floating-ui/dom@1.1.1': - resolution: {integrity: sha512-TpIO93+DIujg3g7SykEAGZMDtbJRrmnYRCNYSjJlvIbGhBjRSNTLVbNeDQBrzy9qDgUbiWdc7KA0uZHZ2tJmiw==} - - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - - '@iconify-json/carbon@1.2.18': - resolution: {integrity: sha512-Grb13E6r/RqTEV4Sqd/BQR2FUt57U2WLuticJ5H8JbTdHLop1LmdePu3EJJA3Xi8DcWRbD6OnC133hKfOwlgtg==} - - '@iconify-json/ph@1.2.2': - resolution: {integrity: sha512-PgkEZNtqa8hBGjHXQa4pMwZa93hmfu8FUSjs/nv4oUU6yLsgv+gh9nu28Kqi8Fz9CCVu4hj1MZs9/60J57IzFw==} - - '@iconify-json/svg-spinners@1.2.4': - resolution: {integrity: sha512-ayn0pogFPwJA1WFZpDnoq9/hjDxN+keeCMyThaX4d3gSJ3y0mdKUxIA/b1YXWGtY9wVtZmxwcvOIeEieG4+JNg==} - - '@iconify/types@2.0.0': - resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - - '@iconify/utils@3.1.0': - resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@leichtgewicht/ip-codec@2.0.5': - resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} - - '@lillallol/outline-pdf-data-structure@1.0.3': - resolution: {integrity: sha512-XlK9dERP2n9afkJ23JyJzpmesLgiOHmhqKuGgeytnT+IVGFdAsYl1wLr2o+byXNAN5fveNbc7CCI6RfBsd5FCw==} - - '@lillallol/outline-pdf@4.0.0': - resolution: {integrity: sha512-tILGNyOdI3ukZfU19TNTDVoS0W1nSPlMxCKAm9FPV4OPL786Ur7e1CRLQZWKJP6uaMQsUqSDBCTzISs6lXWdAQ==} - - '@mdit-vue/plugin-component@3.0.2': - resolution: {integrity: sha512-Fu53MajrZMOAjOIPGMTdTXgHLgGU9KwTqKtYc6WNYtFZNKw04euSfJ/zFg8eBY/2MlciVngkF7Gyc2IL7e8Bsw==} - engines: {node: '>=20.0.0'} - - '@mdit-vue/plugin-frontmatter@3.0.2': - resolution: {integrity: sha512-QKKgIva31YtqHgSAz7S7hRcL7cHXiqdog4wxTfxeQCHo+9IP4Oi5/r1Y5E93nTPccpadDWzAwr3A0F+kAEnsVQ==} - engines: {node: '>=20.0.0'} - - '@mdit-vue/types@3.0.2': - resolution: {integrity: sha512-00aAZ0F0NLik6I6Yba2emGbHLxv+QYrPH00qQ5dFKXlAo1Ll2RHDXwY7nN2WAfrx2pP+WrvSRFTGFCNGdzBDHw==} - engines: {node: '>=20.0.0'} - - '@mermaid-js/parser@1.0.0': - resolution: {integrity: sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@nuxt/kit@3.21.1': - resolution: {integrity: sha512-QORZRjcuTKgo++XP1Pc2c2gqwRydkaExrIRfRI9vFsPA3AzuHVn5Gfmbv1ic8y34e78mr5DMBvJlelUaeOuajg==} - engines: {node: '>=18.12.0'} - - '@pdf-lib/standard-fonts@1.0.0': - resolution: {integrity: sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==} - - '@pdf-lib/upng@1.0.1': - resolution: {integrity: sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==} - - '@polka/url@1.0.0-next.29': - resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - - '@quansync/fs@1.0.0': - resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} - - '@rolldown/pluginutils@1.0.0-rc.2': - resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} - - '@rolldown/pluginutils@1.0.0-rc.6': - resolution: {integrity: sha512-Y0+JT8Mi1mmW08K6HieG315XNRu4L0rkfCpA364HtytjgiqYnMYRdFPcxRl+BQQqNXzecL2S9nii+RUpO93XIA==} - - '@rollup/rollup-android-arm-eabi@4.59.0': - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.59.0': - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.59.0': - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.59.0': - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.59.0': - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.59.0': - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.59.0': - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.59.0': - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-loong64-musl@4.59.0': - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-ppc64-musl@4.59.0': - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.59.0': - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.59.0': - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openbsd-x64@4.59.0': - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.59.0': - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.59.0': - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.59.0': - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.59.0': - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.59.0': - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} - cpu: [x64] - os: [win32] - - '@shikijs/core@3.23.0': - resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} - - '@shikijs/engine-javascript@3.23.0': - resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==} - - '@shikijs/engine-oniguruma@3.23.0': - resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} - - '@shikijs/langs@3.23.0': - resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} - - '@shikijs/markdown-it@3.23.0': - resolution: {integrity: sha512-0tgFk+UUxBDXmdS/3xznAj0hhZWAF88UgpGGfgQppAEohtYKw+5MAxpuPQwa+baK/NbRrGlyfGdcpeXZqqEQSw==} - peerDependencies: - markdown-it-async: ^2.2.0 - peerDependenciesMeta: - markdown-it-async: - optional: true - - '@shikijs/monaco@3.23.0': - resolution: {integrity: sha512-OCApTdAGTHMFUXSYwGztW6EnlxXsWNrpnGf+uO+AznE+khC6V1/8QjuJESIcvZUIq9iAp4ZCNYosZKSVj1Hctg==} - - '@shikijs/themes@3.23.0': - resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} - - '@shikijs/twoslash@3.23.0': - resolution: {integrity: sha512-pNaLJWMA3LU7PhT8tm9OQBZ1epy0jmdgeJzntBtr1EVXLbHxGzTj3mnf9vOdcl84l96qnlJXkJ/NGXZYBpXl5g==} - peerDependencies: - typescript: '>=5.5.0' - - '@shikijs/types@3.23.0': - resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} - - '@shikijs/vitepress-twoslash@3.23.0': - resolution: {integrity: sha512-CnNsKIxxkRxRkL5+m6TNPit563TYfEEqlod8C6N1rfeZvX4xUlRrpoKyoWKmpGSNyjWWeYpMZTUH18YTTOxKfw==} - - '@shikijs/vscode-textmate@10.0.2': - resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - - '@slidev/cli@52.13.0': - resolution: {integrity: sha512-f5A/aGr0+f/EskUPb3frcLFvsxU6WjITP5m9rS1g2q1Vkks1L4Jd2o8WROo4jy1/ALY+W7haeV133WKGPbtzJg==} - engines: {node: '>=18.0.0'} - hasBin: true - peerDependencies: - playwright-chromium: ^1.10.0 - peerDependenciesMeta: - playwright-chromium: - optional: true - - '@slidev/client@52.13.0': - resolution: {integrity: sha512-DN8gjMEqjzYvFeNg+RIp+IKjYEWAHW3Jpq/cGlYEYio7dIqaIt+L1V37Sb3zp5GxTYXxGWnxsn+aUC7cCpN73A==} - engines: {node: '>=18.0.0'} - - '@slidev/parser@52.13.0': - resolution: {integrity: sha512-M/XjHxDePLJfTs3NZc95E5Zww2NNMOPIwC386l+cODJN03GNDwsui1OXXM3Wfr3tTeyBroCTiztWXt+cnrntxA==} - engines: {node: '>=18.0.0'} - - '@slidev/rough-notation@0.1.0': - resolution: {integrity: sha512-a/CbVmjuoO3E4JbUr2HOTsXndbcrdLWOM+ajbSQIY3gmLFzhjeXHGksGcp1NZ08pJjLZyTCxfz1C7v/ltJqycA==} - - '@slidev/theme-default@0.25.0': - resolution: {integrity: sha512-iWvthH1Ny+i6gTwRnEeeU+EiqsHC56UdEO45bqLSNmymRAOWkKUJ/M0o7iahLzHSXsiPu71B7C715WxqjXk2hw==} - engines: {node: '>=14.0.0', slidev: '>=v0.47.0'} - - '@slidev/types@0.47.5': - resolution: {integrity: sha512-X67V4cCgM0Sz50bP8GbVzmiL8DHC2IXvdKcsN7DlxHyf+/T4d9GveeGukwha5Fx3MuYeGZWKag7TFL2ZY4w54A==} - engines: {node: '>=18.0.0'} - - '@slidev/types@52.13.0': - resolution: {integrity: sha512-ff4fkDDsYYYRKOgCF1U+EISidBc1e9EQARnq6anAocKgGHsi1Jq3LG1GY05fjtPRpVNtS4TWN2MWtBMrBP60Rw==} - engines: {node: '>=18.0.0'} - - '@types/d3-array@3.2.2': - resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} - - '@types/d3-axis@3.0.6': - resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} - - '@types/d3-brush@3.0.6': - resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} - - '@types/d3-chord@3.0.6': - resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} - - '@types/d3-color@3.1.3': - resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} - - '@types/d3-contour@3.0.6': - resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} - - '@types/d3-delaunay@6.0.4': - resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} - - '@types/d3-dispatch@3.0.7': - resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} - - '@types/d3-drag@3.0.7': - resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} - - '@types/d3-dsv@3.0.7': - resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} - - '@types/d3-ease@3.0.2': - resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} - - '@types/d3-fetch@3.0.7': - resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} - - '@types/d3-force@3.0.10': - resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} - - '@types/d3-format@3.0.4': - resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} - - '@types/d3-geo@3.1.0': - resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} - - '@types/d3-hierarchy@3.1.7': - resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} - - '@types/d3-interpolate@3.0.4': - resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} - - '@types/d3-path@3.1.1': - resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} - - '@types/d3-polygon@3.0.2': - resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} - - '@types/d3-quadtree@3.0.6': - resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} - - '@types/d3-random@3.0.3': - resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} - - '@types/d3-scale-chromatic@3.1.0': - resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} - - '@types/d3-scale@4.0.9': - resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} - - '@types/d3-selection@3.0.11': - resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} - - '@types/d3-shape@3.1.8': - resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} - - '@types/d3-time-format@4.0.3': - resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} - - '@types/d3-time@3.0.4': - resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} - - '@types/d3-timer@3.0.2': - resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} - - '@types/d3-transition@3.0.9': - resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} - - '@types/d3-zoom@3.0.8': - resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} - - '@types/d3@7.4.3': - resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} - - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/geojson@7946.0.16': - resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} - - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - - '@types/linkify-it@5.0.0': - resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} - - '@types/markdown-it@14.1.2': - resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} - - '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - - '@types/mdurl@2.0.0': - resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} - - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/node@22.19.13': - resolution: {integrity: sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==} - - '@types/trusted-types@2.0.7': - resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - - '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - - '@types/web-bluetooth@0.0.21': - resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} - - '@typescript/ata@0.9.8': - resolution: {integrity: sha512-+M815CeDRJS5H5ciWfhFCKp25nNfF+LFWawWAaBhNlquFb2wS5IIMDI+2bKWN3GuU6mpj+FzySsOD29M4nG8Xg==} - peerDependencies: - typescript: '>=4.4.4' - - '@typescript/vfs@1.6.4': - resolution: {integrity: sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==} - peerDependencies: - typescript: '*' - - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - - '@unhead/vue@2.1.9': - resolution: {integrity: sha512-7SqqDEn5zFID1PnEdjLCLa/kOhoAlzol0JdYfVr2Ejek+H4ON4s8iyExv2QQ8bReMosbXQ/Bw41j2CF1NUuGSA==} - peerDependencies: - vue: '>=3.5.18' - - '@unocss/cli@66.6.2': - resolution: {integrity: sha512-N7nKnOJ/36FRs3PE7+CFbzg7UBhIsucYYAK5xjJScX0H2q8O6rODaNM5uvc77Qh4q+y1S/Bt5ArOwIewzdpP4w==} - engines: {node: '>=14'} - hasBin: true - - '@unocss/config@66.6.2': - resolution: {integrity: sha512-qny2bRW1OA+MZbWShVZdBg6fJundm1LqQwCxJnIpeK3McpPHS3pnHBiwD1wfZHY2z5Pe+XgZOZkozNmG/eyyqg==} - engines: {node: '>=14'} - - '@unocss/core@66.6.2': - resolution: {integrity: sha512-IOvN1BLRP0VTjjS5afSxmXhvKRDko2Shisp8spU+A9qiH1tXEFP3phyVevm/SuGwBHO1lC+SJ451/4oFkCAwJA==} - - '@unocss/extractor-arbitrary-variants@66.6.2': - resolution: {integrity: sha512-D2tK/8QClrVViSuoH5eLjXwlVOK1UgXx7ukz/D260+R6vhCmjv97RXPouZkq40sxGzfxzaQZUyPEjXLjtnO3bw==} - - '@unocss/extractor-mdc@66.6.2': - resolution: {integrity: sha512-P5qRV6PyH49nm548Giy5cUr7aQVVPkPqtyUZYEoSNZhfk5t2ELfqjKVUIzS/Xxix1IkHSkdedkwpqjoOhTh/Tg==} - - '@unocss/inspector@66.6.2': - resolution: {integrity: sha512-q0kktb01dXeeXyNnNwYM1SkSHxrEOQhCZ/YQ5aCdC7BWNGF4yZMK0YrJXmGUTEHN4RhEPLN/rAIsDBsKcoFaAQ==} - - '@unocss/preset-attributify@66.6.2': - resolution: {integrity: sha512-pRry38qO1kJvj5/cekbDk0QLosty+UFQ3fhNiph88D//jkT5tsUCn77nB/RTSe7oTqw/FqNwxPgbGz/wfNWqZg==} - - '@unocss/preset-icons@66.6.2': - resolution: {integrity: sha512-FjhxvYX+21HefYdMIxJCq8C9v/K7fSlO1DMqDQgtrCp0/WvHyFncHILLOwp064M7m3AqzOVJx7Vw/zCvKy0Jrg==} - - '@unocss/preset-mini@66.6.2': - resolution: {integrity: sha512-mybpiAq9htF7PWPH1Mnb4y7hrxVwpsBg8VfbjSglY3SfLca8RrJtvBT+DVh7YUDRiYsZGfihRWkfD0AN68gkcA==} - - '@unocss/preset-tagify@66.6.2': - resolution: {integrity: sha512-ybb45So2x87P3bssLRp1uIS+VHAeNSecwkHqiv93PnuBDJ38/9XlqWF98uga2MEfNM3zvMj9plX9MauidxiPrw==} - - '@unocss/preset-typography@66.6.2': - resolution: {integrity: sha512-1f/ZfeuLQOnO48mRz1+6UdoJxa13ZYcamaLz7ft96n7D1eWvkOUAC/AUUke/kbHh3vvqwRVimC9OpdXxdGFQAQ==} - - '@unocss/preset-uno@66.6.2': - resolution: {integrity: sha512-Wy3V25ZF29OmVHJk5ghP6HCCRNBJXm0t+bKLKJJknOjD+/D51DZbUsDqZBtTpVtgi/SOPDbw7cX3lY2oqt4Hnw==} - - '@unocss/preset-web-fonts@66.6.2': - resolution: {integrity: sha512-0ckqiE8HkhETeghhxCXVGf96sNPhgBsB5q32iAuMM0HFR4x+ANiLqyfKrm/iqxKUw6rVO4+ItTV0RUWKcZvkXg==} - - '@unocss/preset-wind3@66.6.2': - resolution: {integrity: sha512-UqdU2Obx3wXid9xeBHGY1MWxedXa43MGuP5Z2FA9modcXptReux4Zhy764SeQwx6acOUEql2/CTvOBwelZzheQ==} - - '@unocss/preset-wind4@66.6.2': - resolution: {integrity: sha512-XU+4NN9QIMefawDB9FqOeKONXeGDUJQuQgOeBcpbV/jwOYtyqRrHiqQg++fy1hRbluM+S+KqwRHYjvje8zCTow==} - - '@unocss/preset-wind@66.6.2': - resolution: {integrity: sha512-G0H4baUizmTByEowqGuYbKpU2TTisDhZ9W7hrIpYFbRkFv0i1kN2mIxCwj/FLmdY/6x8iSRJ7rO8Nez63YYhnw==} - - '@unocss/reset@66.6.2': - resolution: {integrity: sha512-hBmXE8pJUybUYwFKVZsVy8XyIv3W7htz2ejYuJVpZAQnO4PWPUBb95UcLwBvHWhzZxXRNtvsTtSOsreUvm6mJw==} - - '@unocss/rule-utils@66.6.2': - resolution: {integrity: sha512-cygfCtkeMrqMM6si1cnyOF16sS7M2gCAqgmZybAhGV7tmH7V8Izn52JZiZIrxVRNMz9dWMVWerHEI9nLbFdbrg==} - engines: {node: '>=14'} - - '@unocss/transformer-attributify-jsx@66.6.2': - resolution: {integrity: sha512-WiAEdEowGjQWu1ayhkGGBNGyw3mZLzZ+V5o3zx5U2GPuqvP67YIUfvY+/gTkCnd4+A8unkb+a1VeVgr4cHUkQw==} - - '@unocss/transformer-compile-class@66.6.2': - resolution: {integrity: sha512-L0yaQAmvWkm6LVLXMviqhHIi4c7WQpZFBgJF8jfsALyHihh8K9U9OrRJ81zfLH3Ltw5ZbGzoDE8m/2bB6aRhyw==} - - '@unocss/transformer-directives@66.6.2': - resolution: {integrity: sha512-gjLDLItTUJ4CV8K2AA0cw381a7rJ3U4kCHQmZmN3+956o2R7cEHSLyEczmMy04Mg2JBomrjIZjo+L66z5rvblQ==} - - '@unocss/transformer-variant-group@66.6.2': - resolution: {integrity: sha512-Uoo6xthOHJ36NdN4b7s/Y7R3fZOf4JYgKzuldHEyHAo0LL204Ss+Ah0+TEt4v72aq+Z86vrLJPyYCeGNKdr8cA==} - - '@unocss/vite@66.6.2': - resolution: {integrity: sha512-HLmzDvde3BJ2C6iromHVE21lmNm4SmGSMlbSbFuLPOmWV11XhhHBkAOzytSxPBRG0dbuo+InSGUM14Ek2d6UDg==} - peerDependencies: - vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0-0 - - '@vitejs/plugin-vue-jsx@5.1.4': - resolution: {integrity: sha512-70LmoVk9riR7qc4W2CpjsbNMWTPnuZb9dpFKX1emru0yP57nsc9k8nhLA6U93ngQapv5VDIUq2JatNfLbBIkrA==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - vue: ^3.0.0 - - '@vitejs/plugin-vue@6.0.4': - resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - vue: ^3.2.25 - - '@volar/language-core@2.4.28': - resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} - - '@volar/source-map@2.4.28': - resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} - - '@vue/babel-helper-vue-transform-on@2.0.1': - resolution: {integrity: sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==} - - '@vue/babel-plugin-jsx@2.0.1': - resolution: {integrity: sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - peerDependenciesMeta: - '@babel/core': - optional: true - - '@vue/babel-plugin-resolve-type@2.0.1': - resolution: {integrity: sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@vue/compiler-core@3.5.29': - resolution: {integrity: sha512-cuzPhD8fwRHk8IGfmYaR4eEe4cAyJEL66Ove/WZL7yWNL134nqLddSLwNRIsFlnnW1kK+p8Ck3viFnC0chXCXw==} - - '@vue/compiler-dom@3.5.29': - resolution: {integrity: sha512-n0G5o7R3uBVmVxjTIYcz7ovr8sy7QObFG8OQJ3xGCDNhbG60biP/P5KnyY8NLd81OuT1WJflG7N4KWYHaeeaIg==} - - '@vue/compiler-sfc@3.5.29': - resolution: {integrity: sha512-oJZhN5XJs35Gzr50E82jg2cYdZQ78wEwvRO6Y63TvLVTc+6xICzJHP1UIecdSPPYIbkautNBanDiWYa64QSFIA==} - - '@vue/compiler-ssr@3.5.29': - resolution: {integrity: sha512-Y/ARJZE6fpjzL5GH/phJmsFwx3g6t2KmHKHx5q+MLl2kencADKIrhH5MLF6HHpRMmlRAYBRSvv347Mepf1zVNw==} - - '@vue/devtools-api@6.6.4': - resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} - - '@vue/language-core@3.2.5': - resolution: {integrity: sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==} - - '@vue/reactivity@3.5.29': - resolution: {integrity: sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA==} - - '@vue/runtime-core@3.5.29': - resolution: {integrity: sha512-8DpW2QfdwIWOLqtsNcds4s+QgwSaHSJY/SUe04LptianUQ/0xi6KVsu/pYVh+HO3NTVvVJjIPL2t6GdeKbS4Lg==} - - '@vue/runtime-dom@3.5.29': - resolution: {integrity: sha512-AHvvJEtcY9tw/uk+s/YRLSlxxQnqnAkjqvK25ZiM4CllCZWzElRAoQnCM42m9AHRLNJ6oe2kC5DCgD4AUdlvXg==} - - '@vue/server-renderer@3.5.29': - resolution: {integrity: sha512-G/1k6WK5MusLlbxSE2YTcqAAezS+VuwHhOvLx2KnQU7G2zCH6KIb+5Wyt6UjMq7a3qPzNEjJXs1hvAxDclQH+g==} - peerDependencies: - vue: 3.5.29 - - '@vue/shared@3.5.29': - resolution: {integrity: sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg==} - - '@vueuse/core@13.9.0': - resolution: {integrity: sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==} - peerDependencies: - vue: ^3.5.0 - - '@vueuse/core@14.2.1': - resolution: {integrity: sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==} - peerDependencies: - vue: ^3.5.0 - - '@vueuse/math@14.2.1': - resolution: {integrity: sha512-WV4WTm4GBeILnIAOePQNI1UbYv/HjDx1P+0MSXxFyBy3r8I9xVYn6xqBMLkCbXfAVmkr1sA/G5ILM2K8VDtIbA==} - peerDependencies: - vue: ^3.5.0 - - '@vueuse/metadata@13.9.0': - resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==} - - '@vueuse/metadata@14.2.1': - resolution: {integrity: sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==} - - '@vueuse/motion@3.0.3': - resolution: {integrity: sha512-4B+ITsxCI9cojikvrpaJcLXyq0spj3sdlzXjzesWdMRd99hhtFI6OJ/1JsqwtF73YooLe0hUn/xDR6qCtmn5GQ==} - peerDependencies: - vue: '>=3.0.0' - - '@vueuse/shared@13.9.0': - resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==} - peerDependencies: - vue: ^3.5.0 - - '@vueuse/shared@14.2.1': - resolution: {integrity: sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==} - peerDependencies: - vue: ^3.5.0 - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - alien-signals@3.1.2: - resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} - - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} - engines: {node: '>=14'} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - baseline-browser-mapping@2.10.0: - resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} - engines: {node: '>=6.0.0'} - hasBin: true - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - birpc@2.9.0: - resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - bundle-name@4.1.0: - resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} - engines: {node: '>=18'} - - c12@3.3.3: - resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==} - peerDependencies: - magicast: '*' - peerDependenciesMeta: - magicast: - optional: true - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - caniuse-lite@1.0.30001774: - resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==} - - ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - - character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - - character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - - character-entities@2.0.2: - resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - - chevrotain-allstar@0.3.1: - resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} - peerDependencies: - chevrotain: ^11.0.0 - - chevrotain@11.1.1: - resolution: {integrity: sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - chokidar@5.0.0: - resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} - engines: {node: '>= 20.19.0'} - - citty@0.1.6: - resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - - citty@0.2.1: - resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} - - cli-progress@3.12.0: - resolution: {integrity: sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==} - engines: {node: '>=4'} - - cliui@9.0.1: - resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} - engines: {node: '>=20'} - - clone-regexp@3.0.0: - resolution: {integrity: sha512-ujdnoq2Kxb8s3ItNBtnYeXdm07FcU0u8ARAT1lQ2YdMwQC+cdiXX8KoqMVuglztILivceTtp4ivqGSmEmhBUJw==} - engines: {node: '>=12'} - - codemirror-theme-vars@0.1.2: - resolution: {integrity: sha512-WTau8X2q58b0SOAY9DO+iQVw8JKVEgyQIqArp2D732tcc+pobbMta3bnVMdQdmgwuvNrOFFr6HoxPRoQOgooFA==} - - colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - - comma-separated-tokens@2.0.3: - resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - - commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} - - commander@8.3.0: - resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} - engines: {node: '>= 12'} - - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - - confbox@0.2.4: - resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} - - connect@3.7.0: - resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} - engines: {node: '>= 0.10.0'} - - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - - convert-hrtime@5.0.0: - resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} - engines: {node: '>=12'} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - - cose-base@1.0.3: - resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} - - cose-base@2.2.0: - resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} - - css-tree@3.1.0: - resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - cytoscape-cose-bilkent@4.1.0: - resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} - peerDependencies: - cytoscape: ^3.2.0 - - cytoscape-fcose@2.2.0: - resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} - peerDependencies: - cytoscape: ^3.2.0 - - cytoscape@3.33.1: - resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==} - engines: {node: '>=0.10'} - - d3-array@2.12.1: - resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} - - d3-array@3.2.4: - resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} - engines: {node: '>=12'} - - d3-axis@3.0.0: - resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} - engines: {node: '>=12'} - - d3-brush@3.0.0: - resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} - engines: {node: '>=12'} - - d3-chord@3.0.1: - resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} - engines: {node: '>=12'} - - d3-color@3.1.0: - resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} - engines: {node: '>=12'} - - d3-contour@4.0.2: - resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} - engines: {node: '>=12'} - - d3-delaunay@6.0.4: - resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} - engines: {node: '>=12'} - - d3-dispatch@3.0.1: - resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} - engines: {node: '>=12'} - - d3-drag@3.0.0: - resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} - engines: {node: '>=12'} - - d3-dsv@3.0.1: - resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} - engines: {node: '>=12'} - hasBin: true - - d3-ease@3.0.1: - resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} - engines: {node: '>=12'} - - d3-fetch@3.0.1: - resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} - engines: {node: '>=12'} - - d3-force@3.0.0: - resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} - engines: {node: '>=12'} - - d3-format@3.1.2: - resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} - engines: {node: '>=12'} - - d3-geo@3.1.1: - resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} - engines: {node: '>=12'} - - d3-hierarchy@3.1.2: - resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} - engines: {node: '>=12'} - - d3-interpolate@3.0.1: - resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} - engines: {node: '>=12'} - - d3-path@1.0.9: - resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} - - d3-path@3.1.0: - resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} - engines: {node: '>=12'} - - d3-polygon@3.0.1: - resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} - engines: {node: '>=12'} - - d3-quadtree@3.0.1: - resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} - engines: {node: '>=12'} - - d3-random@3.0.1: - resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} - engines: {node: '>=12'} - - d3-sankey@0.12.3: - resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} - - d3-scale-chromatic@3.1.0: - resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} - engines: {node: '>=12'} - - d3-scale@4.0.2: - resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} - engines: {node: '>=12'} - - d3-selection@3.0.0: - resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} - engines: {node: '>=12'} - - d3-shape@1.3.7: - resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} - - d3-shape@3.2.0: - resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} - engines: {node: '>=12'} - - d3-time-format@4.1.0: - resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} - engines: {node: '>=12'} - - d3-time@3.1.0: - resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} - engines: {node: '>=12'} - - d3-timer@3.0.1: - resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} - engines: {node: '>=12'} - - d3-transition@3.0.1: - resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} - engines: {node: '>=12'} - peerDependencies: - d3-selection: 2 - 3 - - d3-zoom@3.0.0: - resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} - engines: {node: '>=12'} - - d3@7.9.0: - resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} - engines: {node: '>=12'} - - dagre-d3-es@7.0.13: - resolution: {integrity: sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==} - - dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} - - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decode-named-character-reference@1.3.0: - resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} - - default-browser-id@5.0.1: - resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} - engines: {node: '>=18'} - - default-browser@5.5.0: - resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} - engines: {node: '>=18'} - - define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} - - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - - delaunator@5.0.1: - resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - destr@2.0.5: - resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - - devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - - diff-match-patch-es@1.0.1: - resolution: {integrity: sha512-KhSofrZDERg/NE6Nd+TK53knp2qz0o2Ix8rhkXd3Chfm7Wlo58Eq/juNmkyS6bS+3xS26L3Pstz3BdY/q+e9UQ==} - - dns-packet@5.6.1: - resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} - engines: {node: '>=6'} - - dns-socket@4.2.2: - resolution: {integrity: sha512-BDeBd8najI4/lS00HSKpdFia+OvUMytaVjfzR9n5Lq8MlZRSvtbI+uLtx1+XmQFls5wFU9dssccTmQQ6nfpjdg==} - engines: {node: '>=6'} - - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - - dompurify@3.2.7: - resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} - - dompurify@3.3.1: - resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} - - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - - dotenv@17.3.1: - resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} - engines: {node: '>=12'} - - drauu@1.0.0: - resolution: {integrity: sha512-K3a1cbP2l4i0H/bmNM4nyGsY5/hiH5a10sEHlksqKue0+TPQCHrV9DwPad+St06CJwpkdzVJ/FyOYTIAm82rgg==} - - duplexer@0.1.2: - resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - electron-to-chromium@1.5.302: - resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} - - emoji-regex@10.6.0: - resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - entities@7.0.1: - resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} - engines: {node: '>=0.12'} - - error-stack-parser-es@1.0.5: - resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} - - errx@0.1.0: - resolution: {integrity: sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==} - - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - exsolve@1.0.8: - resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - - extend-shallow@2.0.1: - resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} - engines: {node: '>=0.10.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-saver@2.0.5: - resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - finalhandler@1.1.2: - resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} - engines: {node: '>= 0.8'} - - floating-vue@5.2.2: - resolution: {integrity: sha512-afW+h2CFafo+7Y9Lvw/xsqjaQlKLdJV7h1fCHfcYQ1C4SVMlu7OAekqWgu5d4SgvkBVU0pVpLlVsrSTBURFRkg==} - peerDependencies: - '@nuxt/kit': ^3.2.0 - vue: ^3.2.0 - peerDependenciesMeta: - '@nuxt/kit': - optional: true - - framesync@6.1.2: - resolution: {integrity: sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-timeout@0.1.1: - resolution: {integrity: sha512-0NVVC0TaP7dSTvn1yMiy6d6Q8gifzbvQafO46RtLG/kHJUBNd+pVRGOBoK44wNBvtSPUJRfdVvkFdD3p0xvyZg==} - engines: {node: '>=14.16'} - - fuse.js@7.1.0: - resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} - engines: {node: '>=10'} - - fzf@0.5.2: - resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-east-asian-width@1.5.0: - resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} - engines: {node: '>=18'} - - get-port-please@3.2.0: - resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} - - giget@2.0.0: - resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} - hasBin: true - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - global-directory@4.0.1: - resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} - engines: {node: '>=18'} - - globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - - gray-matter@4.0.3: - resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} - engines: {node: '>=6.0'} - - gzip-size@6.0.0: - resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} - engines: {node: '>=10'} - - hachure-fill@0.5.2: - resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} - - hast-util-to-html@9.0.5: - resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} - - hast-util-whitespace@3.0.0: - resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - - hey-listen@1.0.8: - resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} - - hookable@6.0.1: - resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} - - html-void-elements@3.0.0: - resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - - htmlparser2@10.1.0: - resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - - https@1.0.0: - resolution: {integrity: sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - image-size@1.2.1: - resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} - engines: {node: '>=16.x'} - hasBin: true - - immediate@3.0.6: - resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ini@4.1.1: - resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - internmap@1.0.1: - resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} - - internmap@2.0.3: - resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} - engines: {node: '>=12'} - - ip-regex@5.0.0: - resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true - - is-extendable@0.1.1: - resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} - engines: {node: '>=0.10.0'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-in-ssh@1.0.0: - resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} - engines: {node: '>=20'} - - is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - - is-installed-globally@1.0.0: - resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} - engines: {node: '>=18'} - - is-ip@5.0.1: - resolution: {integrity: sha512-FCsGHdlrOnZQcp0+XT5a+pYowf33itBalCl+7ovNXC/7o5BhIpG14M3OrpPPdBSIQJCm+0M5+9mO7S9VVTTCFw==} - engines: {node: '>=14.16'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-path-inside@4.0.0: - resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} - engines: {node: '>=12'} - - is-regexp@3.1.0: - resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} - engines: {node: '>=12'} - - is-wsl@3.1.1: - resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} - engines: {node: '>=16'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} - hasBin: true - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@3.14.2: - resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} - hasBin: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jszip@3.10.1: - resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} - - katex@0.16.33: - resolution: {integrity: sha512-q3N5u+1sY9Bu7T4nlXoiRBXWfwSefNGoKeOwekV+gw0cAXQlz2Ww6BLcmBxVDeXBMUDQv6fK5bcNaJLxob3ZQA==} - hasBin: true - - khroma@2.1.0: - resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} - - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - - klona@2.0.6: - resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} - engines: {node: '>= 8'} - - knitwork@1.3.0: - resolution: {integrity: sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==} - - langium@4.2.1: - resolution: {integrity: sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==} - engines: {node: '>=20.10.0', npm: '>=10.2.3'} - - layout-base@1.0.2: - resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} - - layout-base@2.0.1: - resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} - - lie@3.3.0: - resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - - linkify-it@5.0.0: - resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - - local-pkg@1.1.2: - resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} - engines: {node: '>=14'} - - lodash-es@4.17.23: - resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} - - longest-streak@3.1.0: - resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - - magic-string-stack@1.1.0: - resolution: {integrity: sha512-eAjQQ16Woyi71/6gQoLvn9Mte0JDoS5zUV/BMk0Pzs8Fou+nEuo5T0UbLWBhm3mXiK2YnFz2lFpEEVcLcohhVw==} - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - markdown-exit@1.0.0-beta.8: - resolution: {integrity: sha512-LuwW1iurvRspcUJlgMk/QBC2is+aOqRDwseGQA3wYrUwadVvMYpxazx6ZKxxyIkLuQhV40M/3E4lU4qIavsAlA==} - - markdown-it-footnote@4.0.0: - resolution: {integrity: sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==} - - markdown-it-mdc@0.2.12: - resolution: {integrity: sha512-kXdgH+wvEFw1KaFDL+IdjJijtjDBj0bhhvVANvl9bhRokkyhcGEd1HCYsj336YqJHihgMEYcbGWLm/qjLMTdzg==} - peerDependencies: - '@types/markdown-it': '*' - markdown-it: ^14.0.0 - - markdown-it@14.1.1: - resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} - hasBin: true - - markdown-table@3.0.4: - resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - - marked@14.0.0: - resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} - engines: {node: '>= 18'} - hasBin: true - - marked@16.4.2: - resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} - engines: {node: '>= 20'} - hasBin: true - - mdast-util-find-and-replace@3.0.2: - resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - - mdast-util-from-markdown@2.0.3: - resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} - - mdast-util-gfm-autolink-literal@2.0.1: - resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} - - mdast-util-gfm-footnote@2.1.0: - resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} - - mdast-util-gfm-strikethrough@2.0.0: - resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} - - mdast-util-gfm-table@2.0.0: - resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} - - mdast-util-gfm-task-list-item@2.0.0: - resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} - - mdast-util-gfm@3.1.0: - resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} - - mdast-util-phrasing@4.1.0: - resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - - mdast-util-to-hast@13.2.1: - resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} - - mdast-util-to-markdown@2.1.2: - resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} - - mdast-util-to-string@4.0.0: - resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} - - mdn-data@2.12.2: - resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} - - mdurl@2.0.0: - resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - mermaid@11.12.3: - resolution: {integrity: sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==} - - micromark-core-commonmark@2.0.3: - resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} - - micromark-factory-destination@2.0.1: - resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} - - micromark-factory-label@2.0.1: - resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} - - micromark-factory-space@2.0.1: - resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} - - micromark-factory-title@2.0.1: - resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} - - micromark-factory-whitespace@2.0.1: - resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} - - micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - - micromark-util-chunked@2.0.1: - resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} - - micromark-util-classify-character@2.0.1: - resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} - - micromark-util-combine-extensions@2.0.1: - resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} - - micromark-util-decode-numeric-character-reference@2.0.2: - resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} - - micromark-util-decode-string@2.0.1: - resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} - - micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - - micromark-util-html-tag-name@2.0.1: - resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} - - micromark-util-normalize-identifier@2.0.1: - resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} - - micromark-util-resolve-all@2.0.1: - resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} - - micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - - micromark-util-subtokenize@2.1.0: - resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} - - micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - - micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - - micromark@4.0.2: - resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mlly@1.8.0: - resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} - - monaco-editor@0.55.1: - resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} - - mrmime@2.0.1: - resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} - engines: {node: '>=10'} - - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - muggle-string@0.4.1: - resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - nanotar@0.2.1: - resolution: {integrity: sha512-MUrzzDUcIOPbv7ubhDV/L4CIfVTATd9XhDE2ixFeCrM5yp9AlzUpn91JrnN0HD6hksdxvz9IW9aKANz0Bta0GA==} - - node-fetch-native@1.6.7: - resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} - - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - nypm@0.6.5: - resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==} - engines: {node: '>=18'} - hasBin: true - - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - - ofetch@1.5.1: - resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} - - ohash@2.0.11: - resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - - on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} - - oniguruma-parser@0.12.1: - resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} - - oniguruma-to-es@4.3.4: - resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} - - open@10.2.0: - resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} - engines: {node: '>=18'} - - open@11.0.0: - resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} - engines: {node: '>=20'} - - p-map@7.0.4: - resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} - engines: {node: '>=18'} - - package-manager-detector@1.6.0: - resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} - - pako@1.0.11: - resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - - path-data-parser@0.1.0: - resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} - - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - pdf-lib@1.17.1: - resolution: {integrity: sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==} - - perfect-debounce@2.1.0: - resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - - pkg-types@2.3.0: - resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - - plantuml-encoder@1.4.0: - resolution: {integrity: sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==} - - playwright-chromium@1.58.2: - resolution: {integrity: sha512-SCoQ3hjBs7FfO46CoOtgAUg77BuYwCni1bzQgm47IUyLBTipnGkLxLnaUNRKXvPYO4hAyt8++Z6wVShVnhrzmw==} - engines: {node: '>=18'} - hasBin: true - - playwright-core@1.58.2: - resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==} - engines: {node: '>=18'} - hasBin: true - - points-on-curve@0.2.0: - resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} - - points-on-path@0.2.1: - resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} - - popmotion@11.0.5: - resolution: {integrity: sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==} - - postcss-nested@7.0.2: - resolution: {integrity: sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==} - engines: {node: '>=18.0'} - peerDependencies: - postcss: ^8.2.14 - - postcss-selector-parser@7.1.1: - resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} - engines: {node: '>=4'} - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - - powershell-utils@0.1.0: - resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} - engines: {node: '>=20'} - - pptxgenjs@4.0.1: - resolution: {integrity: sha512-TeJISr8wouAuXw4C1F/mC33xbZs/FuEG6nH9FG1Zj+nuPcGMP5YRHl6X+j3HSUnS1f3at6k75ZZXPMZlA5Lj9A==} - - prism-theme-vars@0.2.5: - resolution: {integrity: sha512-/D8gBTScYzi9afwE6v3TC1U/1YFZ6k+ly17mtVRdLpGy7E79YjJJWkXFgUDHJ2gDksV/ZnXF7ydJ4TvoDm2z/Q==} - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - - property-information@7.1.0: - resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} - - public-ip@8.0.0: - resolution: {integrity: sha512-XzVyz98rNQiTRciAC+I4w45fWWxM9KKedDGNtH4unPwBcWo2Y9n7kgPXqlTiWqKN0EFlIIU1i8yrWOy9mxgZ8g==} - engines: {node: '>=20'} - - punycode.js@2.3.1: - resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} - engines: {node: '>=6'} - - quansync@0.2.11: - resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} - - quansync@1.0.0: - resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - queue@6.0.2: - resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} - - rc9@2.1.2: - resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} - - rc9@3.0.0: - resolution: {integrity: sha512-MGOue0VqscKWQ104udASX/3GYDcKyPI4j4F8gu/jHHzglpmy9a/anZK3PNe8ug6aZFl+9GxLtdhe3kVZuMaQbA==} - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - readdirp@5.0.0: - resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} - engines: {node: '>= 20.19.0'} - - recordrtc@5.6.2: - resolution: {integrity: sha512-1QNKKNtl7+KcwD1lyOgP3ZlbiJ1d0HtXnypUy7yq49xEERxk31PHvE9RCciDrulPCY7WJ+oz0R9hpNxgsIurGQ==} - - regex-recursion@6.0.2: - resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} - - regex-utilities@2.3.0: - resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - - regex@6.1.0: - resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - resolve-global@2.0.0: - resolution: {integrity: sha512-gnAQ0Q/KkupGkuiMyX4L0GaBV8iFwlmoXsMtOz+DFTaKmHhOO/dSlP1RMKhpvHv/dh6K/IQkowGJBqUG0NfBUw==} - engines: {node: '>=18'} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - robust-predicates@3.0.2: - resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} - - rollup@4.59.0: - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - roughjs@4.6.6: - resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} - - run-applescript@7.1.0: - resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} - engines: {node: '>=18'} - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - rw@1.3.3: - resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - scule@1.3.0: - resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} - - section-matter@1.0.0: - resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} - engines: {node: '>=4'} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - - shiki-magic-move@1.2.1: - resolution: {integrity: sha512-421QfXnBNbsyOkb+gh/Sm18SSedN7pVc+ZA4gMCEF6YPtvEIntP5CojBiVz9AL0apCRsWeiZfVBEmw0oUP+uMg==} - peerDependencies: - react: ^18.2.0 || ^19.0.0 - shiki: ^1.0.0 || ^2.0.0 || ^3.0.0 - solid-js: ^1.9.1 - svelte: ^5.0.0-0 - vue: ^3.4.0 - peerDependenciesMeta: - react: - optional: true - shiki: - optional: true - solid-js: - optional: true - svelte: - optional: true - vue: - optional: true - - shiki@3.23.0: - resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==} - - sirv@3.0.2: - resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} - engines: {node: '>=18'} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - space-separated-tokens@2.0.2: - resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@7.2.0: - resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} - engines: {node: '>=18'} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - - stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - - strip-bom-string@1.0.0: - resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} - engines: {node: '>=0.10.0'} - - style-value-types@5.1.2: - resolution: {integrity: sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q==} - - stylis@4.3.6: - resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} - - super-regex@0.2.0: - resolution: {integrity: sha512-WZzIx3rC1CvbMDloLsVw0lkZVKJWbrkJ0k1ghKFmcnPrW1+jWbgTkTEWVtD9lMdmI4jZEz40+naBxl1dCUhXXw==} - engines: {node: '>=14.16'} - - time-span@5.1.0: - resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} - engines: {node: '>=12'} - - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} - engines: {node: '>=18'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - totalist@3.0.1: - resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} - engines: {node: '>=6'} - - trim-lines@3.0.1: - resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - - ts-dedent@2.2.0: - resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} - engines: {node: '>=6.10'} - - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - - tslib@2.4.0: - resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} - - twoslash-protocol@0.3.6: - resolution: {integrity: sha512-FHGsJ9Q+EsNr5bEbgG3hnbkvEBdW5STgPU824AHUjB4kw0Dn4p8tABT7Ncg1Ie6V0+mDg3Qpy41VafZXcQhWMA==} - - twoslash-vue@0.3.6: - resolution: {integrity: sha512-HXYxU+Y7jZiMXJN4980fQNMYflLD8uqKey1qVW5ri8bqYTm2t5ILmOoCOli7esdCHlMq4/No3iQUWBWDhZNs9w==} - peerDependencies: - typescript: ^5.5.0 - - twoslash@0.3.6: - resolution: {integrity: sha512-VuI5OKl+MaUO9UIW3rXKoPgHI3X40ZgB/j12VY6h98Ae1mCBihjPvhOPeJWlxCYcmSbmeZt5ZKkK0dsVtp+6pA==} - peerDependencies: - typescript: ^5.5.0 - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - uc.micro@2.1.0: - resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} - - unconfig-core@7.5.0: - resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} - - unconfig@7.5.0: - resolution: {integrity: sha512-oi8Qy2JV4D3UQ0PsopR28CzdQ3S/5A1zwsUwp/rosSbfhJ5z7b90bIyTwi/F7hCLD4SGcZVjDzd4XoUQcEanvA==} - - unctx@2.5.0: - resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - unhead@2.1.9: - resolution: {integrity: sha512-4GvP6YeJQzo9J3g9fFZUJOH6jacUp5JgJ0/zC8eZrt8Dwompg9SuOSfrYbZaEzsfMPgQc4fsEjMoY9WzGPOChg==} - - unist-util-is@6.0.1: - resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} - - unist-util-position@5.0.0: - resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} - - unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - - unist-util-visit-parents@6.0.2: - resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - - unist-util-visit@5.1.0: - resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} - - unocss@66.6.2: - resolution: {integrity: sha512-ulkfFBFm++/yTdgDn/clpxtm3GxynZi57F4KETQkMQWRXUI7FwqPKGn0xooscvbtldlX67pkovwj/mzkwExitQ==} - engines: {node: '>=14'} - peerDependencies: - '@unocss/astro': 66.6.2 - '@unocss/postcss': 66.6.2 - '@unocss/webpack': 66.6.2 - peerDependenciesMeta: - '@unocss/astro': - optional: true - '@unocss/postcss': - optional: true - '@unocss/webpack': - optional: true - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - unplugin-icons@23.0.1: - resolution: {integrity: sha512-rv0XEJepajKzDLvRUWASM8K+8+/CCfZn2jtogXqg6RIp7kpatRc/aFrVJn8ANQA09e++lPEEv9yX8cC9enc+QQ==} - peerDependencies: - '@svgr/core': '>=7.0.0' - '@svgx/core': ^1.0.1 - '@vue/compiler-sfc': ^3.0.2 - svelte: ^3.0.0 || ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - '@svgr/core': - optional: true - '@svgx/core': - optional: true - '@vue/compiler-sfc': - optional: true - svelte: - optional: true - - unplugin-utils@0.3.1: - resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} - engines: {node: '>=20.19.0'} - - unplugin-vue-components@31.0.0: - resolution: {integrity: sha512-4ULwfTZTLuWJ7+S9P7TrcStYLsSRkk6vy2jt/WTfgUEUb0nW9//xxmrfhyHUEVpZ2UKRRwfRb8Yy15PDbVZf+Q==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@nuxt/kit': ^3.2.2 || ^4.0.0 - vue: ^3.0.0 - peerDependenciesMeta: - '@nuxt/kit': - optional: true - - unplugin-vue-markdown@30.0.0: - resolution: {integrity: sha512-FVdKAb7jmZslfdkOCfm6jxHaUafltBpOXdoLvKY+0I0EeMmhxXTSzeDldwXFJeV0IH8LyIXIiU29E6gv02WJFQ==} - engines: {node: '>=20'} - peerDependencies: - vite: ^2.0.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0 - - unplugin@2.3.11: - resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} - engines: {node: '>=18.12.0'} - - untun@0.1.3: - resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} - hasBin: true - - untyped@2.0.0: - resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} - hasBin: true - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uqr@0.1.2: - resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - uuid@11.1.0: - resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} - hasBin: true - - vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} - - vfile@6.0.3: - resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - - vite-dev-rpc@1.1.0: - resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==} - peerDependencies: - vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 - - vite-hot-client@2.1.0: - resolution: {integrity: sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==} - peerDependencies: - vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 - - vite-plugin-inspect@11.3.3: - resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==} - engines: {node: '>=14'} - peerDependencies: - '@nuxt/kit': '*' - vite: ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - '@nuxt/kit': - optional: true - - vite-plugin-remote-assets@2.1.0: - resolution: {integrity: sha512-8ajL5WG5BmYcC8zxeLOa3byCUG2AopKDAdNK7zStPHaRYYz1mxXBaeNFLu6vTEXj8UmXAsb5WlEmBBYwtlPEwA==} - peerDependencies: - vite: '>=5.0.0' - - vite-plugin-static-copy@3.2.0: - resolution: {integrity: sha512-g2k9z8B/1Bx7D4wnFjPLx9dyYGrqWMLTpwTtPHhcU+ElNZP2O4+4OsyaficiDClus0dzVhdGvoGFYMJxoXZ12Q==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - - vite-plugin-vue-server-ref@1.0.0: - resolution: {integrity: sha512-6d/JZVrnETM0xa0AVyEcI1bXFpEzQ1EPU5N/gDa7NtXo/7nfJWJhezcWq82Jih6Vf8xtGJjhi1w19AcXAtwmAg==} - peerDependencies: - vite: '>=2.0.0' - vue: ^3.0.0 - - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vitefu@1.1.2: - resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==} - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0 - peerDependenciesMeta: - vite: - optional: true - - vscode-jsonrpc@8.2.0: - resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} - engines: {node: '>=14.0.0'} - - vscode-languageserver-protocol@3.17.5: - resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} - - vscode-languageserver-textdocument@1.0.12: - resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} - - vscode-languageserver-types@3.17.5: - resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} - - vscode-languageserver@9.0.1: - resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} - hasBin: true - - vscode-uri@3.1.0: - resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} - - vue-resize@2.0.0-alpha.1: - resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==} - peerDependencies: - vue: ^3.0.0 - - vue-router@4.6.4: - resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} - peerDependencies: - vue: ^3.5.0 - - vue@3.5.29: - resolution: {integrity: sha512-BZqN4Ze6mDQVNAni0IHeMJ5mwr8VAJ3MQC9FmprRhcBYENw+wOAAjRj8jfmN6FLl0j96OXbR+CjWhmAmM+QGnA==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - webpack-virtual-modules@0.6.2: - resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - - wrap-ansi@9.0.2: - resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} - engines: {node: '>=18'} - - wsl-utils@0.1.0: - resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} - engines: {node: '>=18'} - - wsl-utils@0.3.1: - resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} - engines: {node: '>=20'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} - engines: {node: '>= 14.6'} - hasBin: true - - yargs-parser@22.0.0: - resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - - yargs@18.0.0: - resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - - zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - -snapshots: - - '@antfu/install-pkg@1.1.0': - dependencies: - package-manager-detector: 1.6.0 - tinyexec: 1.0.2 - - '@antfu/ni@28.2.0': - dependencies: - ansis: 4.2.0 - fzf: 0.5.2 - package-manager-detector: 1.6.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - - '@antfu/utils@9.3.0': {} - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.0': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-annotate-as-pure@7.27.3': - dependencies: - '@babel/types': 7.29.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.0 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-member-expression-to-functions@7.28.5': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-optimise-call-expression@7.27.1': - dependencies: - '@babel/types': 7.29.0 - - '@babel/helper-plugin-utils@7.28.6': {} - - '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.6': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.27.7': - dependencies: - '@babel/types': 7.29.0 - - '@babel/parser@7.29.0': - dependencies: - '@babel/types': 7.29.0 - - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - - '@babel/traverse@7.27.7': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/parser': 7.27.7 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@braintree/sanitize-url@7.1.2': {} - - '@chevrotain/cst-dts-gen@11.1.1': - dependencies: - '@chevrotain/gast': 11.1.1 - '@chevrotain/types': 11.1.1 - lodash-es: 4.17.23 - - '@chevrotain/gast@11.1.1': - dependencies: - '@chevrotain/types': 11.1.1 - lodash-es: 4.17.23 - - '@chevrotain/regexp-to-ast@11.1.1': {} - - '@chevrotain/types@11.1.1': {} - - '@chevrotain/utils@11.1.1': {} - - '@drauu/core@1.0.0': {} - - '@esbuild/aix-ppc64@0.27.3': - optional: true - - '@esbuild/android-arm64@0.27.3': - optional: true - - '@esbuild/android-arm@0.27.3': - optional: true - - '@esbuild/android-x64@0.27.3': - optional: true - - '@esbuild/darwin-arm64@0.27.3': - optional: true - - '@esbuild/darwin-x64@0.27.3': - optional: true - - '@esbuild/freebsd-arm64@0.27.3': - optional: true - - '@esbuild/freebsd-x64@0.27.3': - optional: true - - '@esbuild/linux-arm64@0.27.3': - optional: true - - '@esbuild/linux-arm@0.27.3': - optional: true - - '@esbuild/linux-ia32@0.27.3': - optional: true - - '@esbuild/linux-loong64@0.27.3': - optional: true - - '@esbuild/linux-mips64el@0.27.3': - optional: true - - '@esbuild/linux-ppc64@0.27.3': - optional: true - - '@esbuild/linux-riscv64@0.27.3': - optional: true - - '@esbuild/linux-s390x@0.27.3': - optional: true - - '@esbuild/linux-x64@0.27.3': - optional: true - - '@esbuild/netbsd-arm64@0.27.3': - optional: true - - '@esbuild/netbsd-x64@0.27.3': - optional: true - - '@esbuild/openbsd-arm64@0.27.3': - optional: true - - '@esbuild/openbsd-x64@0.27.3': - optional: true - - '@esbuild/openharmony-arm64@0.27.3': - optional: true - - '@esbuild/sunos-x64@0.27.3': - optional: true - - '@esbuild/win32-arm64@0.27.3': - optional: true - - '@esbuild/win32-ia32@0.27.3': - optional: true - - '@esbuild/win32-x64@0.27.3': - optional: true - - '@floating-ui/core@1.7.4': - dependencies: - '@floating-ui/utils': 0.2.10 - - '@floating-ui/dom@1.1.1': - dependencies: - '@floating-ui/core': 1.7.4 - - '@floating-ui/utils@0.2.10': {} - - '@iconify-json/carbon@1.2.18': - dependencies: - '@iconify/types': 2.0.0 - - '@iconify-json/ph@1.2.2': - dependencies: - '@iconify/types': 2.0.0 - - '@iconify-json/svg-spinners@1.2.4': - dependencies: - '@iconify/types': 2.0.0 - - '@iconify/types@2.0.0': {} - - '@iconify/utils@3.1.0': - dependencies: - '@antfu/install-pkg': 1.1.0 - '@iconify/types': 2.0.0 - mlly: 1.8.0 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@leichtgewicht/ip-codec@2.0.5': {} - - '@lillallol/outline-pdf-data-structure@1.0.3': {} - - '@lillallol/outline-pdf@4.0.0': - dependencies: - '@lillallol/outline-pdf-data-structure': 1.0.3 - pdf-lib: 1.17.1 - - '@mdit-vue/plugin-component@3.0.2': - dependencies: - '@types/markdown-it': 14.1.2 - markdown-it: 14.1.1 - - '@mdit-vue/plugin-frontmatter@3.0.2': - dependencies: - '@mdit-vue/types': 3.0.2 - '@types/markdown-it': 14.1.2 - gray-matter: 4.0.3 - markdown-it: 14.1.1 - - '@mdit-vue/types@3.0.2': {} - - '@mermaid-js/parser@1.0.0': - dependencies: - langium: 4.2.1 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - - '@nuxt/kit@3.21.1': - dependencies: - c12: 3.3.3 - consola: 3.4.2 - defu: 6.1.4 - destr: 2.0.5 - errx: 0.1.0 - exsolve: 1.0.8 - ignore: 7.0.5 - jiti: 2.6.1 - klona: 2.0.6 - knitwork: 1.3.0 - mlly: 1.8.0 - ohash: 2.0.11 - pathe: 2.0.3 - pkg-types: 2.3.0 - rc9: 3.0.0 - scule: 1.3.0 - semver: 7.7.4 - tinyglobby: 0.2.15 - ufo: 1.6.3 - unctx: 2.5.0 - untyped: 2.0.0 - transitivePeerDependencies: - - magicast - optional: true - - '@pdf-lib/standard-fonts@1.0.0': - dependencies: - pako: 1.0.11 - - '@pdf-lib/upng@1.0.1': - dependencies: - pako: 1.0.11 - - '@polka/url@1.0.0-next.29': {} - - '@quansync/fs@1.0.0': - dependencies: - quansync: 1.0.0 - - '@rolldown/pluginutils@1.0.0-rc.2': {} - - '@rolldown/pluginutils@1.0.0-rc.6': {} - - '@rollup/rollup-android-arm-eabi@4.59.0': - optional: true - - '@rollup/rollup-android-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-x64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.59.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.59.0': - optional: true - - '@rollup/rollup-openbsd-x64@4.59.0': - optional: true - - '@rollup/rollup-openharmony-arm64@4.59.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.59.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.59.0': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.59.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.59.0': - optional: true - - '@shikijs/core@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - hast-util-to-html: 9.0.5 - - '@shikijs/engine-javascript@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - '@shikijs/vscode-textmate': 10.0.2 - oniguruma-to-es: 4.3.4 - - '@shikijs/engine-oniguruma@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - '@shikijs/vscode-textmate': 10.0.2 - - '@shikijs/langs@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - - '@shikijs/markdown-it@3.23.0': - dependencies: - markdown-it: 14.1.1 - shiki: 3.23.0 - - '@shikijs/monaco@3.23.0': - dependencies: - '@shikijs/core': 3.23.0 - '@shikijs/types': 3.23.0 - '@shikijs/vscode-textmate': 10.0.2 - - '@shikijs/themes@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - - '@shikijs/twoslash@3.23.0(typescript@5.9.3)': - dependencies: - '@shikijs/core': 3.23.0 - '@shikijs/types': 3.23.0 - twoslash: 0.3.6(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@shikijs/types@3.23.0': - dependencies: - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - '@shikijs/vitepress-twoslash@3.23.0(@nuxt/kit@3.21.1)(typescript@5.9.3)': - dependencies: - '@shikijs/twoslash': 3.23.0(typescript@5.9.3) - floating-vue: 5.2.2(@nuxt/kit@3.21.1)(vue@3.5.29(typescript@5.9.3)) - lz-string: 1.5.0 - magic-string: 0.30.21 - markdown-it: 14.1.1 - mdast-util-from-markdown: 2.0.3 - mdast-util-gfm: 3.1.0 - mdast-util-to-hast: 13.2.1 - ohash: 2.0.11 - shiki: 3.23.0 - twoslash: 0.3.6(typescript@5.9.3) - twoslash-vue: 0.3.6(typescript@5.9.3) - vue: 3.5.29(typescript@5.9.3) - transitivePeerDependencies: - - '@nuxt/kit' - - supports-color - - typescript - - '@shikijs/vscode-textmate@10.0.2': {} - - '@slidev/cli@52.13.0(@nuxt/kit@3.21.1)(@types/markdown-it@14.1.2)(@types/node@22.19.13)(@vue/compiler-sfc@3.5.29)(markdown-it@14.1.1)(playwright-chromium@1.58.2)(postcss@8.5.6)': - dependencies: - '@antfu/ni': 28.2.0 - '@antfu/utils': 9.3.0 - '@iconify-json/carbon': 1.2.18 - '@iconify-json/ph': 1.2.2 - '@iconify-json/svg-spinners': 1.2.4 - '@lillallol/outline-pdf': 4.0.0 - '@shikijs/markdown-it': 3.23.0 - '@shikijs/twoslash': 3.23.0(typescript@5.9.3) - '@shikijs/vitepress-twoslash': 3.23.0(@nuxt/kit@3.21.1)(typescript@5.9.3) - '@slidev/client': 52.13.0(@nuxt/kit@3.21.1)(@vue/compiler-sfc@3.5.29)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - '@slidev/parser': 52.13.0(@nuxt/kit@3.21.1)(@vue/compiler-sfc@3.5.29)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - '@slidev/types': 52.13.0(@nuxt/kit@3.21.1)(@vue/compiler-sfc@3.5.29)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - '@unocss/extractor-mdc': 66.6.2 - '@unocss/reset': 66.6.2 - '@vitejs/plugin-vue': 6.0.4(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3)) - '@vitejs/plugin-vue-jsx': 5.1.4(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3)) - ansis: 4.2.0 - chokidar: 5.0.0 - cli-progress: 3.12.0 - connect: 3.7.0 - fast-deep-equal: 3.1.3 - fast-glob: 3.3.3 - get-port-please: 3.2.0 - global-directory: 4.0.1 - htmlparser2: 10.1.0 - is-installed-globally: 1.0.0 - jiti: 2.6.1 - katex: 0.16.33 - local-pkg: 1.1.2 - lz-string: 1.5.0 - magic-string: 0.30.21 - magic-string-stack: 1.1.0 - markdown-exit: 1.0.0-beta.8 - markdown-it-footnote: 4.0.0 - markdown-it-mdc: 0.2.12(@types/markdown-it@14.1.2)(markdown-it@14.1.1) - mlly: 1.8.0 - monaco-editor: 0.55.1 - obug: 2.1.1 - open: 11.0.0 - pdf-lib: 1.17.1 - picomatch: 4.0.3 - plantuml-encoder: 1.4.0 - postcss-nested: 7.0.2(postcss@8.5.6) - pptxgenjs: 4.0.1 - prompts: 2.4.2 - public-ip: 8.0.0 - resolve-from: 5.0.0 - resolve-global: 2.0.0 - semver: 7.7.4 - shiki: 3.23.0 - shiki-magic-move: 1.2.1(shiki@3.23.0)(vue@3.5.29(typescript@5.9.3)) - sirv: 3.0.2 - source-map-js: 1.2.1 - typescript: 5.9.3 - unhead: 2.1.9 - unocss: 66.6.2(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - unplugin-icons: 23.0.1(@vue/compiler-sfc@3.5.29) - unplugin-vue-components: 31.0.0(@nuxt/kit@3.21.1)(vue@3.5.29(typescript@5.9.3)) - unplugin-vue-markdown: 30.0.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - untun: 0.1.3 - uqr: 0.1.2 - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - vite-plugin-inspect: 11.3.3(@nuxt/kit@3.21.1)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - vite-plugin-remote-assets: 2.1.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - vite-plugin-static-copy: 3.2.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - vite-plugin-vue-server-ref: 1.0.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3)) - vitefu: 1.1.2(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - vue: 3.5.29(typescript@5.9.3) - yaml: 2.8.2 - yargs: 18.0.0 - optionalDependencies: - playwright-chromium: 1.58.2 - transitivePeerDependencies: - - '@nuxt/kit' - - '@svgr/core' - - '@svgx/core' - - '@types/markdown-it' - - '@types/node' - - '@unocss/astro' - - '@unocss/postcss' - - '@unocss/webpack' - - '@vue/compiler-sfc' - - less - - lightningcss - - magicast - - markdown-it - - markdown-it-async - - postcss - - react - - sass - - sass-embedded - - solid-js - - stylus - - sugarss - - supports-color - - svelte - - terser - - tsx - - '@slidev/client@52.13.0(@nuxt/kit@3.21.1)(@vue/compiler-sfc@3.5.29)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))': - dependencies: - '@antfu/utils': 9.3.0 - '@iconify-json/carbon': 1.2.18 - '@iconify-json/ph': 1.2.2 - '@iconify-json/svg-spinners': 1.2.4 - '@shikijs/engine-javascript': 3.23.0 - '@shikijs/monaco': 3.23.0 - '@shikijs/vitepress-twoslash': 3.23.0(@nuxt/kit@3.21.1)(typescript@5.9.3) - '@slidev/parser': 52.13.0(@nuxt/kit@3.21.1)(@vue/compiler-sfc@3.5.29)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - '@slidev/rough-notation': 0.1.0 - '@slidev/types': 52.13.0(@nuxt/kit@3.21.1)(@vue/compiler-sfc@3.5.29)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - '@typescript/ata': 0.9.8(typescript@5.9.3) - '@unhead/vue': 2.1.9(vue@3.5.29(typescript@5.9.3)) - '@unocss/reset': 66.6.2 - '@vueuse/core': 14.2.1(vue@3.5.29(typescript@5.9.3)) - '@vueuse/math': 14.2.1(vue@3.5.29(typescript@5.9.3)) - '@vueuse/motion': 3.0.3(vue@3.5.29(typescript@5.9.3)) - ansis: 4.2.0 - drauu: 1.0.0 - file-saver: 2.0.5 - floating-vue: 5.2.2(@nuxt/kit@3.21.1)(vue@3.5.29(typescript@5.9.3)) - fuse.js: 7.1.0 - katex: 0.16.33 - lz-string: 1.5.0 - mermaid: 11.12.3 - monaco-editor: 0.55.1 - nanotar: 0.2.1 - pptxgenjs: 4.0.1 - recordrtc: 5.6.2 - shiki: 3.23.0 - shiki-magic-move: 1.2.1(shiki@3.23.0)(vue@3.5.29(typescript@5.9.3)) - typescript: 5.9.3 - unocss: 66.6.2(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - vue: 3.5.29(typescript@5.9.3) - vue-router: 4.6.4(vue@3.5.29(typescript@5.9.3)) - yaml: 2.8.2 - transitivePeerDependencies: - - '@nuxt/kit' - - '@svgr/core' - - '@svgx/core' - - '@unocss/astro' - - '@unocss/postcss' - - '@unocss/webpack' - - '@vue/compiler-sfc' - - magicast - - markdown-it-async - - react - - solid-js - - supports-color - - svelte - - vite - - '@slidev/parser@52.13.0(@nuxt/kit@3.21.1)(@vue/compiler-sfc@3.5.29)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))': - dependencies: - '@antfu/utils': 9.3.0 - '@slidev/types': 52.13.0(@nuxt/kit@3.21.1)(@vue/compiler-sfc@3.5.29)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - yaml: 2.8.2 - transitivePeerDependencies: - - '@nuxt/kit' - - '@svgr/core' - - '@svgx/core' - - '@unocss/astro' - - '@unocss/postcss' - - '@unocss/webpack' - - '@vue/compiler-sfc' - - markdown-it-async - - supports-color - - svelte - - typescript - - vite - - '@slidev/rough-notation@0.1.0': - dependencies: - roughjs: 4.6.6 - - '@slidev/theme-default@0.25.0': - dependencies: - '@slidev/types': 0.47.5 - codemirror-theme-vars: 0.1.2 - prism-theme-vars: 0.2.5 - - '@slidev/types@0.47.5': {} - - '@slidev/types@52.13.0(@nuxt/kit@3.21.1)(@vue/compiler-sfc@3.5.29)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))': - dependencies: - '@antfu/utils': 9.3.0 - '@shikijs/markdown-it': 3.23.0 - '@vitejs/plugin-vue': 6.0.4(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3)) - '@vitejs/plugin-vue-jsx': 5.1.4(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3)) - katex: 0.16.33 - mermaid: 11.12.3 - monaco-editor: 0.55.1 - shiki: 3.23.0 - unocss: 66.6.2(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - unplugin-icons: 23.0.1(@vue/compiler-sfc@3.5.29) - unplugin-vue-markdown: 30.0.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - vite-plugin-inspect: 11.3.3(@nuxt/kit@3.21.1)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - vite-plugin-remote-assets: 2.1.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - vite-plugin-static-copy: 3.2.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - vite-plugin-vue-server-ref: 1.0.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3)) - vue: 3.5.29(typescript@5.9.3) - vue-router: 4.6.4(vue@3.5.29(typescript@5.9.3)) - transitivePeerDependencies: - - '@nuxt/kit' - - '@svgr/core' - - '@svgx/core' - - '@unocss/astro' - - '@unocss/postcss' - - '@unocss/webpack' - - '@vue/compiler-sfc' - - markdown-it-async - - supports-color - - svelte - - typescript - - vite - - '@types/d3-array@3.2.2': {} - - '@types/d3-axis@3.0.6': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-brush@3.0.6': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-chord@3.0.6': {} - - '@types/d3-color@3.1.3': {} - - '@types/d3-contour@3.0.6': - dependencies: - '@types/d3-array': 3.2.2 - '@types/geojson': 7946.0.16 - - '@types/d3-delaunay@6.0.4': {} - - '@types/d3-dispatch@3.0.7': {} - - '@types/d3-drag@3.0.7': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-dsv@3.0.7': {} - - '@types/d3-ease@3.0.2': {} - - '@types/d3-fetch@3.0.7': - dependencies: - '@types/d3-dsv': 3.0.7 - - '@types/d3-force@3.0.10': {} - - '@types/d3-format@3.0.4': {} - - '@types/d3-geo@3.1.0': - dependencies: - '@types/geojson': 7946.0.16 - - '@types/d3-hierarchy@3.1.7': {} - - '@types/d3-interpolate@3.0.4': - dependencies: - '@types/d3-color': 3.1.3 - - '@types/d3-path@3.1.1': {} - - '@types/d3-polygon@3.0.2': {} - - '@types/d3-quadtree@3.0.6': {} - - '@types/d3-random@3.0.3': {} - - '@types/d3-scale-chromatic@3.1.0': {} - - '@types/d3-scale@4.0.9': - dependencies: - '@types/d3-time': 3.0.4 - - '@types/d3-selection@3.0.11': {} - - '@types/d3-shape@3.1.8': - dependencies: - '@types/d3-path': 3.1.1 - - '@types/d3-time-format@4.0.3': {} - - '@types/d3-time@3.0.4': {} - - '@types/d3-timer@3.0.2': {} - - '@types/d3-transition@3.0.9': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-zoom@3.0.8': - dependencies: - '@types/d3-interpolate': 3.0.4 - '@types/d3-selection': 3.0.11 - - '@types/d3@7.4.3': - dependencies: - '@types/d3-array': 3.2.2 - '@types/d3-axis': 3.0.6 - '@types/d3-brush': 3.0.6 - '@types/d3-chord': 3.0.6 - '@types/d3-color': 3.1.3 - '@types/d3-contour': 3.0.6 - '@types/d3-delaunay': 6.0.4 - '@types/d3-dispatch': 3.0.7 - '@types/d3-drag': 3.0.7 - '@types/d3-dsv': 3.0.7 - '@types/d3-ease': 3.0.2 - '@types/d3-fetch': 3.0.7 - '@types/d3-force': 3.0.10 - '@types/d3-format': 3.0.4 - '@types/d3-geo': 3.1.0 - '@types/d3-hierarchy': 3.1.7 - '@types/d3-interpolate': 3.0.4 - '@types/d3-path': 3.1.1 - '@types/d3-polygon': 3.0.2 - '@types/d3-quadtree': 3.0.6 - '@types/d3-random': 3.0.3 - '@types/d3-scale': 4.0.9 - '@types/d3-scale-chromatic': 3.1.0 - '@types/d3-selection': 3.0.11 - '@types/d3-shape': 3.1.8 - '@types/d3-time': 3.0.4 - '@types/d3-time-format': 4.0.3 - '@types/d3-timer': 3.0.2 - '@types/d3-transition': 3.0.9 - '@types/d3-zoom': 3.0.8 - - '@types/debug@4.1.12': - dependencies: - '@types/ms': 2.1.0 - - '@types/estree@1.0.8': {} - - '@types/geojson@7946.0.16': {} - - '@types/hast@3.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/linkify-it@5.0.0': {} - - '@types/markdown-it@14.1.2': - dependencies: - '@types/linkify-it': 5.0.0 - '@types/mdurl': 2.0.0 - - '@types/mdast@4.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/mdurl@2.0.0': {} - - '@types/ms@2.1.0': {} - - '@types/node@22.19.13': - dependencies: - undici-types: 6.21.0 - - '@types/trusted-types@2.0.7': - optional: true - - '@types/unist@3.0.3': {} - - '@types/web-bluetooth@0.0.21': {} - - '@typescript/ata@0.9.8(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript/vfs@1.6.4(typescript@5.9.3)': - dependencies: - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@ungap/structured-clone@1.3.0': {} - - '@unhead/vue@2.1.9(vue@3.5.29(typescript@5.9.3))': - dependencies: - hookable: 6.0.1 - unhead: 2.1.9 - vue: 3.5.29(typescript@5.9.3) - - '@unocss/cli@66.6.2': - dependencies: - '@jridgewell/remapping': 2.3.5 - '@unocss/config': 66.6.2 - '@unocss/core': 66.6.2 - '@unocss/preset-wind3': 66.6.2 - '@unocss/preset-wind4': 66.6.2 - '@unocss/transformer-directives': 66.6.2 - cac: 6.7.14 - chokidar: 5.0.0 - colorette: 2.0.20 - consola: 3.4.2 - magic-string: 0.30.21 - pathe: 2.0.3 - perfect-debounce: 2.1.0 - tinyglobby: 0.2.15 - unplugin-utils: 0.3.1 - - '@unocss/config@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - colorette: 2.0.20 - consola: 3.4.2 - unconfig: 7.5.0 - - '@unocss/core@66.6.2': {} - - '@unocss/extractor-arbitrary-variants@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - - '@unocss/extractor-mdc@66.6.2': {} - - '@unocss/inspector@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - '@unocss/rule-utils': 66.6.2 - colorette: 2.0.20 - gzip-size: 6.0.0 - sirv: 3.0.2 - - '@unocss/preset-attributify@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - - '@unocss/preset-icons@66.6.2': - dependencies: - '@iconify/utils': 3.1.0 - '@unocss/core': 66.6.2 - ofetch: 1.5.1 - - '@unocss/preset-mini@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - '@unocss/extractor-arbitrary-variants': 66.6.2 - '@unocss/rule-utils': 66.6.2 - - '@unocss/preset-tagify@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - - '@unocss/preset-typography@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - '@unocss/rule-utils': 66.6.2 - - '@unocss/preset-uno@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - '@unocss/preset-wind3': 66.6.2 - - '@unocss/preset-web-fonts@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - ofetch: 1.5.1 - - '@unocss/preset-wind3@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - '@unocss/preset-mini': 66.6.2 - '@unocss/rule-utils': 66.6.2 - - '@unocss/preset-wind4@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - '@unocss/extractor-arbitrary-variants': 66.6.2 - '@unocss/rule-utils': 66.6.2 - - '@unocss/preset-wind@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - '@unocss/preset-wind3': 66.6.2 - - '@unocss/reset@66.6.2': {} - - '@unocss/rule-utils@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - magic-string: 0.30.21 - - '@unocss/transformer-attributify-jsx@66.6.2': - dependencies: - '@babel/parser': 7.27.7 - '@babel/traverse': 7.27.7 - '@unocss/core': 66.6.2 - transitivePeerDependencies: - - supports-color - - '@unocss/transformer-compile-class@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - - '@unocss/transformer-directives@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - '@unocss/rule-utils': 66.6.2 - css-tree: 3.1.0 - - '@unocss/transformer-variant-group@66.6.2': - dependencies: - '@unocss/core': 66.6.2 - - '@unocss/vite@66.6.2(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))': - dependencies: - '@jridgewell/remapping': 2.3.5 - '@unocss/config': 66.6.2 - '@unocss/core': 66.6.2 - '@unocss/inspector': 66.6.2 - chokidar: 5.0.0 - magic-string: 0.30.21 - pathe: 2.0.3 - tinyglobby: 0.2.15 - unplugin-utils: 0.3.1 - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - - '@vitejs/plugin-vue-jsx@5.1.4(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-rc.6 - '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.0) - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - vue: 3.5.29(typescript@5.9.3) - transitivePeerDependencies: - - supports-color - - '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))': - dependencies: - '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - vue: 3.5.29(typescript@5.9.3) - - '@volar/language-core@2.4.28': - dependencies: - '@volar/source-map': 2.4.28 - - '@volar/source-map@2.4.28': {} - - '@vue/babel-helper-vue-transform-on@2.0.1': {} - - '@vue/babel-plugin-jsx@2.0.1(@babel/core@7.29.0)': - dependencies: - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@vue/babel-helper-vue-transform-on': 2.0.1 - '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.29.0) - '@vue/shared': 3.5.29 - optionalDependencies: - '@babel/core': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.29.0)': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/parser': 7.29.0 - '@vue/compiler-sfc': 3.5.29 - transitivePeerDependencies: - - supports-color - - '@vue/compiler-core@3.5.29': - dependencies: - '@babel/parser': 7.29.0 - '@vue/shared': 3.5.29 - entities: 7.0.1 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - - '@vue/compiler-dom@3.5.29': - dependencies: - '@vue/compiler-core': 3.5.29 - '@vue/shared': 3.5.29 - - '@vue/compiler-sfc@3.5.29': - dependencies: - '@babel/parser': 7.29.0 - '@vue/compiler-core': 3.5.29 - '@vue/compiler-dom': 3.5.29 - '@vue/compiler-ssr': 3.5.29 - '@vue/shared': 3.5.29 - estree-walker: 2.0.2 - magic-string: 0.30.21 - postcss: 8.5.6 - source-map-js: 1.2.1 - - '@vue/compiler-ssr@3.5.29': - dependencies: - '@vue/compiler-dom': 3.5.29 - '@vue/shared': 3.5.29 - - '@vue/devtools-api@6.6.4': {} - - '@vue/language-core@3.2.5': - dependencies: - '@volar/language-core': 2.4.28 - '@vue/compiler-dom': 3.5.29 - '@vue/shared': 3.5.29 - alien-signals: 3.1.2 - muggle-string: 0.4.1 - path-browserify: 1.0.1 - picomatch: 4.0.3 - - '@vue/reactivity@3.5.29': - dependencies: - '@vue/shared': 3.5.29 - - '@vue/runtime-core@3.5.29': - dependencies: - '@vue/reactivity': 3.5.29 - '@vue/shared': 3.5.29 - - '@vue/runtime-dom@3.5.29': - dependencies: - '@vue/reactivity': 3.5.29 - '@vue/runtime-core': 3.5.29 - '@vue/shared': 3.5.29 - csstype: 3.2.3 - - '@vue/server-renderer@3.5.29(vue@3.5.29(typescript@5.9.3))': - dependencies: - '@vue/compiler-ssr': 3.5.29 - '@vue/shared': 3.5.29 - vue: 3.5.29(typescript@5.9.3) - - '@vue/shared@3.5.29': {} - - '@vueuse/core@13.9.0(vue@3.5.29(typescript@5.9.3))': - dependencies: - '@types/web-bluetooth': 0.0.21 - '@vueuse/metadata': 13.9.0 - '@vueuse/shared': 13.9.0(vue@3.5.29(typescript@5.9.3)) - vue: 3.5.29(typescript@5.9.3) - - '@vueuse/core@14.2.1(vue@3.5.29(typescript@5.9.3))': - dependencies: - '@types/web-bluetooth': 0.0.21 - '@vueuse/metadata': 14.2.1 - '@vueuse/shared': 14.2.1(vue@3.5.29(typescript@5.9.3)) - vue: 3.5.29(typescript@5.9.3) - - '@vueuse/math@14.2.1(vue@3.5.29(typescript@5.9.3))': - dependencies: - '@vueuse/shared': 14.2.1(vue@3.5.29(typescript@5.9.3)) - vue: 3.5.29(typescript@5.9.3) - - '@vueuse/metadata@13.9.0': {} - - '@vueuse/metadata@14.2.1': {} - - '@vueuse/motion@3.0.3(vue@3.5.29(typescript@5.9.3))': - dependencies: - '@vueuse/core': 13.9.0(vue@3.5.29(typescript@5.9.3)) - '@vueuse/shared': 13.9.0(vue@3.5.29(typescript@5.9.3)) - defu: 6.1.4 - framesync: 6.1.2 - popmotion: 11.0.5 - style-value-types: 5.1.2 - vue: 3.5.29(typescript@5.9.3) - optionalDependencies: - '@nuxt/kit': 3.21.1 - transitivePeerDependencies: - - magicast - - '@vueuse/shared@13.9.0(vue@3.5.29(typescript@5.9.3))': - dependencies: - vue: 3.5.29(typescript@5.9.3) - - '@vueuse/shared@14.2.1(vue@3.5.29(typescript@5.9.3))': - dependencies: - vue: 3.5.29(typescript@5.9.3) - - acorn@8.16.0: {} - - alien-signals@3.1.2: {} - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@6.2.3: {} - - ansis@4.2.0: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - - argparse@2.0.1: {} - - baseline-browser-mapping@2.10.0: {} - - binary-extensions@2.3.0: {} - - birpc@2.9.0: {} - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.10.0 - caniuse-lite: 1.0.30001774 - electron-to-chromium: 1.5.302 - node-releases: 2.0.27 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - - bundle-name@4.1.0: - dependencies: - run-applescript: 7.1.0 - - c12@3.3.3: - dependencies: - chokidar: 5.0.0 - confbox: 0.2.4 - defu: 6.1.4 - dotenv: 17.3.1 - exsolve: 1.0.8 - giget: 2.0.0 - jiti: 2.6.1 - ohash: 2.0.11 - pathe: 2.0.3 - perfect-debounce: 2.1.0 - pkg-types: 2.3.0 - rc9: 2.1.2 - optional: true - - cac@6.7.14: {} - - caniuse-lite@1.0.30001774: {} - - ccount@2.0.1: {} - - character-entities-html4@2.1.0: {} - - character-entities-legacy@3.0.0: {} - - character-entities@2.0.2: {} - - chevrotain-allstar@0.3.1(chevrotain@11.1.1): - dependencies: - chevrotain: 11.1.1 - lodash-es: 4.17.23 - - chevrotain@11.1.1: - dependencies: - '@chevrotain/cst-dts-gen': 11.1.1 - '@chevrotain/gast': 11.1.1 - '@chevrotain/regexp-to-ast': 11.1.1 - '@chevrotain/types': 11.1.1 - '@chevrotain/utils': 11.1.1 - lodash-es: 4.17.23 - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - chokidar@5.0.0: - dependencies: - readdirp: 5.0.0 - - citty@0.1.6: - dependencies: - consola: 3.4.2 - - citty@0.2.1: - optional: true - - cli-progress@3.12.0: - dependencies: - string-width: 4.2.3 - - cliui@9.0.1: - dependencies: - string-width: 7.2.0 - strip-ansi: 7.2.0 - wrap-ansi: 9.0.2 - - clone-regexp@3.0.0: - dependencies: - is-regexp: 3.1.0 - - codemirror-theme-vars@0.1.2: {} - - colorette@2.0.20: {} - - comma-separated-tokens@2.0.3: {} - - commander@7.2.0: {} - - commander@8.3.0: {} - - confbox@0.1.8: {} - - confbox@0.2.4: {} - - connect@3.7.0: - dependencies: - debug: 2.6.9 - finalhandler: 1.1.2 - parseurl: 1.3.3 - utils-merge: 1.0.1 - transitivePeerDependencies: - - supports-color - - consola@3.4.2: {} - - convert-hrtime@5.0.0: {} - - convert-source-map@2.0.0: {} - - core-util-is@1.0.3: {} - - cose-base@1.0.3: - dependencies: - layout-base: 1.0.2 - - cose-base@2.2.0: - dependencies: - layout-base: 2.0.1 - - css-tree@3.1.0: - dependencies: - mdn-data: 2.12.2 - source-map-js: 1.2.1 - - cssesc@3.0.0: {} - - csstype@3.2.3: {} - - cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): - dependencies: - cose-base: 1.0.3 - cytoscape: 3.33.1 - - cytoscape-fcose@2.2.0(cytoscape@3.33.1): - dependencies: - cose-base: 2.2.0 - cytoscape: 3.33.1 - - cytoscape@3.33.1: {} - - d3-array@2.12.1: - dependencies: - internmap: 1.0.1 - - d3-array@3.2.4: - dependencies: - internmap: 2.0.3 - - d3-axis@3.0.0: {} - - d3-brush@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - d3-chord@3.0.1: - dependencies: - d3-path: 3.1.0 - - d3-color@3.1.0: {} - - d3-contour@4.0.2: - dependencies: - d3-array: 3.2.4 - - d3-delaunay@6.0.4: - dependencies: - delaunator: 5.0.1 - - d3-dispatch@3.0.1: {} - - d3-drag@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-selection: 3.0.0 - - d3-dsv@3.0.1: - dependencies: - commander: 7.2.0 - iconv-lite: 0.6.3 - rw: 1.3.3 - - d3-ease@3.0.1: {} - - d3-fetch@3.0.1: - dependencies: - d3-dsv: 3.0.1 - - d3-force@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-quadtree: 3.0.1 - d3-timer: 3.0.1 - - d3-format@3.1.2: {} - - d3-geo@3.1.1: - dependencies: - d3-array: 3.2.4 - - d3-hierarchy@3.1.2: {} - - d3-interpolate@3.0.1: - dependencies: - d3-color: 3.1.0 - - d3-path@1.0.9: {} - - d3-path@3.1.0: {} - - d3-polygon@3.0.1: {} - - d3-quadtree@3.0.1: {} - - d3-random@3.0.1: {} - - d3-sankey@0.12.3: - dependencies: - d3-array: 2.12.1 - d3-shape: 1.3.7 - - d3-scale-chromatic@3.1.0: - dependencies: - d3-color: 3.1.0 - d3-interpolate: 3.0.1 - - d3-scale@4.0.2: - dependencies: - d3-array: 3.2.4 - d3-format: 3.1.2 - d3-interpolate: 3.0.1 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - - d3-selection@3.0.0: {} - - d3-shape@1.3.7: - dependencies: - d3-path: 1.0.9 - - d3-shape@3.2.0: - dependencies: - d3-path: 3.1.0 - - d3-time-format@4.1.0: - dependencies: - d3-time: 3.1.0 - - d3-time@3.1.0: - dependencies: - d3-array: 3.2.4 - - d3-timer@3.0.1: {} - - d3-transition@3.0.1(d3-selection@3.0.0): - dependencies: - d3-color: 3.1.0 - d3-dispatch: 3.0.1 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-timer: 3.0.1 - - d3-zoom@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - d3@7.9.0: - dependencies: - d3-array: 3.2.4 - d3-axis: 3.0.0 - d3-brush: 3.0.0 - d3-chord: 3.0.1 - d3-color: 3.1.0 - d3-contour: 4.0.2 - d3-delaunay: 6.0.4 - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-dsv: 3.0.1 - d3-ease: 3.0.1 - d3-fetch: 3.0.1 - d3-force: 3.0.0 - d3-format: 3.1.2 - d3-geo: 3.1.1 - d3-hierarchy: 3.1.2 - d3-interpolate: 3.0.1 - d3-path: 3.1.0 - d3-polygon: 3.0.1 - d3-quadtree: 3.0.1 - d3-random: 3.0.1 - d3-scale: 4.0.2 - d3-scale-chromatic: 3.1.0 - d3-selection: 3.0.0 - d3-shape: 3.2.0 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - d3-timer: 3.0.1 - d3-transition: 3.0.1(d3-selection@3.0.0) - d3-zoom: 3.0.0 - - dagre-d3-es@7.0.13: - dependencies: - d3: 7.9.0 - lodash-es: 4.17.23 - - dayjs@1.11.19: {} - - debug@2.6.9: - dependencies: - ms: 2.0.0 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decode-named-character-reference@1.3.0: - dependencies: - character-entities: 2.0.2 - - default-browser-id@5.0.1: {} - - default-browser@5.5.0: - dependencies: - bundle-name: 4.1.0 - default-browser-id: 5.0.1 - - define-lazy-prop@3.0.0: {} - - defu@6.1.4: {} - - delaunator@5.0.1: - dependencies: - robust-predicates: 3.0.2 - - dequal@2.0.3: {} - - destr@2.0.5: {} - - devlop@1.1.0: - dependencies: - dequal: 2.0.3 - - diff-match-patch-es@1.0.1: {} - - dns-packet@5.6.1: - dependencies: - '@leichtgewicht/ip-codec': 2.0.5 - - dns-socket@4.2.2: - dependencies: - dns-packet: 5.6.1 - - dom-serializer@2.0.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.5.0 - - domelementtype@2.3.0: {} - - domhandler@5.0.3: - dependencies: - domelementtype: 2.3.0 - - dompurify@3.2.7: - optionalDependencies: - '@types/trusted-types': 2.0.7 - - dompurify@3.3.1: - optionalDependencies: - '@types/trusted-types': 2.0.7 - - domutils@3.2.2: - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - - dotenv@17.3.1: - optional: true - - drauu@1.0.0: - dependencies: - '@drauu/core': 1.0.0 - - duplexer@0.1.2: {} - - ee-first@1.1.1: {} - - electron-to-chromium@1.5.302: {} - - emoji-regex@10.6.0: {} - - emoji-regex@8.0.0: {} - - encodeurl@1.0.2: {} - - entities@4.5.0: {} - - entities@7.0.1: {} - - error-stack-parser-es@1.0.5: {} - - errx@0.1.0: - optional: true - - esbuild@0.27.3: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 - - escalade@3.2.0: {} - - escape-html@1.0.3: {} - - escape-string-regexp@5.0.0: {} - - esprima@4.0.1: {} - - estree-walker@2.0.2: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - optional: true - - exsolve@1.0.8: {} - - extend-shallow@2.0.1: - dependencies: - is-extendable: 0.1.1 - - fast-deep-equal@3.1.3: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - file-saver@2.0.5: {} - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - finalhandler@1.1.2: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.3.0 - parseurl: 1.3.3 - statuses: 1.5.0 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - floating-vue@5.2.2(@nuxt/kit@3.21.1)(vue@3.5.29(typescript@5.9.3)): - dependencies: - '@floating-ui/dom': 1.1.1 - vue: 3.5.29(typescript@5.9.3) - vue-resize: 2.0.0-alpha.1(vue@3.5.29(typescript@5.9.3)) - optionalDependencies: - '@nuxt/kit': 3.21.1 - - framesync@6.1.2: - dependencies: - tslib: 2.4.0 - - fsevents@2.3.3: - optional: true - - function-timeout@0.1.1: {} - - fuse.js@7.1.0: {} - - fzf@0.5.2: {} - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-east-asian-width@1.5.0: {} - - get-port-please@3.2.0: {} - - giget@2.0.0: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - defu: 6.1.4 - node-fetch-native: 1.6.7 - nypm: 0.6.5 - pathe: 2.0.3 - optional: true - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - global-directory@4.0.1: - dependencies: - ini: 4.1.1 - - globals@11.12.0: {} - - gray-matter@4.0.3: - dependencies: - js-yaml: 3.14.2 - kind-of: 6.0.3 - section-matter: 1.0.0 - strip-bom-string: 1.0.0 - - gzip-size@6.0.0: - dependencies: - duplexer: 0.1.2 - - hachure-fill@0.5.2: {} - - hast-util-to-html@9.0.5: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - comma-separated-tokens: 2.0.3 - hast-util-whitespace: 3.0.0 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - stringify-entities: 4.0.4 - zwitch: 2.0.4 - - hast-util-whitespace@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hey-listen@1.0.8: {} - - hookable@6.0.1: {} - - html-void-elements@3.0.0: {} - - htmlparser2@10.1.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 7.0.1 - - https@1.0.0: {} - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - ignore@7.0.5: - optional: true - - image-size@1.2.1: - dependencies: - queue: 6.0.2 - - immediate@3.0.6: {} - - inherits@2.0.4: {} - - ini@4.1.1: {} - - internmap@1.0.1: {} - - internmap@2.0.3: {} - - ip-regex@5.0.0: {} - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-docker@3.0.0: {} - - is-extendable@0.1.1: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-in-ssh@1.0.0: {} - - is-inside-container@1.0.0: - dependencies: - is-docker: 3.0.0 - - is-installed-globally@1.0.0: - dependencies: - global-directory: 4.0.1 - is-path-inside: 4.0.0 - - is-ip@5.0.1: - dependencies: - ip-regex: 5.0.0 - super-regex: 0.2.0 - - is-number@7.0.0: {} - - is-path-inside@4.0.0: {} - - is-regexp@3.1.0: {} - - is-wsl@3.1.1: - dependencies: - is-inside-container: 1.0.0 - - isarray@1.0.0: {} - - jiti@2.6.1: {} - - js-tokens@4.0.0: {} - - js-yaml@3.14.2: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - jsesc@3.1.0: {} - - json5@2.2.3: {} - - jszip@3.10.1: - dependencies: - lie: 3.3.0 - pako: 1.0.11 - readable-stream: 2.3.8 - setimmediate: 1.0.5 - - katex@0.16.33: - dependencies: - commander: 8.3.0 - - khroma@2.1.0: {} - - kind-of@6.0.3: {} - - kleur@3.0.3: {} - - klona@2.0.6: {} - - knitwork@1.3.0: - optional: true - - langium@4.2.1: - dependencies: - chevrotain: 11.1.1 - chevrotain-allstar: 0.3.1(chevrotain@11.1.1) - vscode-languageserver: 9.0.1 - vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.1.0 - - layout-base@1.0.2: {} - - layout-base@2.0.1: {} - - lie@3.3.0: - dependencies: - immediate: 3.0.6 - - linkify-it@5.0.0: - dependencies: - uc.micro: 2.1.0 - - local-pkg@1.1.2: - dependencies: - mlly: 1.8.0 - pkg-types: 2.3.0 - quansync: 0.2.11 - - lodash-es@4.17.23: {} - - longest-streak@3.1.0: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lz-string@1.5.0: {} - - magic-string-stack@1.1.0: - dependencies: - '@jridgewell/remapping': 2.3.5 - magic-string: 0.30.21 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - markdown-exit@1.0.0-beta.8: - dependencies: - entities: 7.0.1 - linkify-it: 5.0.0 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - - markdown-it-footnote@4.0.0: {} - - markdown-it-mdc@0.2.12(@types/markdown-it@14.1.2)(markdown-it@14.1.1): - dependencies: - '@types/markdown-it': 14.1.2 - markdown-it: 14.1.1 - yaml: 2.8.2 - - markdown-it@14.1.1: - dependencies: - argparse: 2.0.1 - entities: 4.5.0 - linkify-it: 5.0.0 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - - markdown-table@3.0.4: {} - - marked@14.0.0: {} - - marked@16.4.2: {} - - mdast-util-find-and-replace@3.0.2: - dependencies: - '@types/mdast': 4.0.4 - escape-string-regexp: 5.0.0 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - mdast-util-from-markdown@2.0.3: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - mdast-util-to-string: 4.0.0 - micromark: 4.0.2 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-decode-string: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - unist-util-stringify-position: 4.0.0 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-autolink-literal@2.0.1: - dependencies: - '@types/mdast': 4.0.4 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-find-and-replace: 3.0.2 - micromark-util-character: 2.1.1 - - mdast-util-gfm-footnote@2.1.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - micromark-util-normalize-identifier: 2.0.1 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-strikethrough@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-table@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-task-list-item@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm@3.1.0: - dependencies: - mdast-util-from-markdown: 2.0.3 - mdast-util-gfm-autolink-literal: 2.0.1 - mdast-util-gfm-footnote: 2.1.0 - mdast-util-gfm-strikethrough: 2.0.0 - mdast-util-gfm-table: 2.0.0 - mdast-util-gfm-task-list-item: 2.0.0 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-phrasing@4.1.0: - dependencies: - '@types/mdast': 4.0.4 - unist-util-is: 6.0.1 - - mdast-util-to-hast@13.2.1: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.0 - devlop: 1.1.0 - micromark-util-sanitize-uri: 2.0.1 - trim-lines: 3.0.1 - unist-util-position: 5.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - - mdast-util-to-markdown@2.1.2: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - longest-streak: 3.1.0 - mdast-util-phrasing: 4.1.0 - mdast-util-to-string: 4.0.0 - micromark-util-classify-character: 2.0.1 - micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.1.0 - zwitch: 2.0.4 - - mdast-util-to-string@4.0.0: - dependencies: - '@types/mdast': 4.0.4 - - mdn-data@2.12.2: {} - - mdurl@2.0.0: {} - - merge2@1.4.1: {} - - mermaid@11.12.3: - dependencies: - '@braintree/sanitize-url': 7.1.2 - '@iconify/utils': 3.1.0 - '@mermaid-js/parser': 1.0.0 - '@types/d3': 7.4.3 - cytoscape: 3.33.1 - cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.1) - cytoscape-fcose: 2.2.0(cytoscape@3.33.1) - d3: 7.9.0 - d3-sankey: 0.12.3 - dagre-d3-es: 7.0.13 - dayjs: 1.11.19 - dompurify: 3.3.1 - katex: 0.16.33 - khroma: 2.1.0 - lodash-es: 4.17.23 - marked: 16.4.2 - roughjs: 4.6.6 - stylis: 4.3.6 - ts-dedent: 2.2.0 - uuid: 11.1.0 - - micromark-core-commonmark@2.0.3: - dependencies: - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-factory-destination: 2.0.1 - micromark-factory-label: 2.0.1 - micromark-factory-space: 2.0.1 - micromark-factory-title: 2.0.1 - micromark-factory-whitespace: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-classify-character: 2.0.1 - micromark-util-html-tag-name: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-destination@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-label@2.0.1: - dependencies: - devlop: 1.1.0 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-space@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-types: 2.0.2 - - micromark-factory-title@2.0.1: - dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-whitespace@2.0.1: - dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-character@2.1.1: - dependencies: - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-chunked@2.0.1: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-classify-character@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-combine-extensions@2.0.1: - dependencies: - micromark-util-chunked: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-decode-numeric-character-reference@2.0.2: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-decode-string@2.0.1: - dependencies: - decode-named-character-reference: 1.3.0 - micromark-util-character: 2.1.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-symbol: 2.0.1 - - micromark-util-encode@2.0.1: {} - - micromark-util-html-tag-name@2.0.1: {} - - micromark-util-normalize-identifier@2.0.1: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-resolve-all@2.0.1: - dependencies: - micromark-util-types: 2.0.2 - - micromark-util-sanitize-uri@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-encode: 2.0.1 - micromark-util-symbol: 2.0.1 - - micromark-util-subtokenize@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-util-chunked: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-symbol@2.0.1: {} - - micromark-util-types@2.0.2: {} - - micromark@4.0.2: - dependencies: - '@types/debug': 4.1.12 - debug: 4.4.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-combine-extensions: 2.0.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-encode: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - transitivePeerDependencies: - - supports-color - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mlly@1.8.0: - dependencies: - acorn: 8.16.0 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.6.3 - - monaco-editor@0.55.1: - dependencies: - dompurify: 3.2.7 - marked: 14.0.0 - - mrmime@2.0.1: {} - - ms@2.0.0: {} - - ms@2.1.3: {} - - muggle-string@0.4.1: {} - - nanoid@3.3.11: {} - - nanotar@0.2.1: {} - - node-fetch-native@1.6.7: {} - - node-releases@2.0.27: {} - - normalize-path@3.0.0: {} - - nypm@0.6.5: - dependencies: - citty: 0.2.1 - pathe: 2.0.3 - tinyexec: 1.0.2 - optional: true - - obug@2.1.1: {} - - ofetch@1.5.1: - dependencies: - destr: 2.0.5 - node-fetch-native: 1.6.7 - ufo: 1.6.3 - - ohash@2.0.11: {} - - on-finished@2.3.0: - dependencies: - ee-first: 1.1.1 - - oniguruma-parser@0.12.1: {} - - oniguruma-to-es@4.3.4: - dependencies: - oniguruma-parser: 0.12.1 - regex: 6.1.0 - regex-recursion: 6.0.2 - - open@10.2.0: - dependencies: - default-browser: 5.5.0 - define-lazy-prop: 3.0.0 - is-inside-container: 1.0.0 - wsl-utils: 0.1.0 - - open@11.0.0: - dependencies: - default-browser: 5.5.0 - define-lazy-prop: 3.0.0 - is-in-ssh: 1.0.0 - is-inside-container: 1.0.0 - powershell-utils: 0.1.0 - wsl-utils: 0.3.1 - - p-map@7.0.4: {} - - package-manager-detector@1.6.0: {} - - pako@1.0.11: {} - - parseurl@1.3.3: {} - - path-browserify@1.0.1: {} - - path-data-parser@0.1.0: {} - - pathe@1.1.2: {} - - pathe@2.0.3: {} - - pdf-lib@1.17.1: - dependencies: - '@pdf-lib/standard-fonts': 1.0.0 - '@pdf-lib/upng': 1.0.1 - pako: 1.0.11 - tslib: 1.14.1 - - perfect-debounce@2.1.0: {} - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} - - picomatch@4.0.3: {} - - pkg-types@1.3.1: - dependencies: - confbox: 0.1.8 - mlly: 1.8.0 - pathe: 2.0.3 - - pkg-types@2.3.0: - dependencies: - confbox: 0.2.4 - exsolve: 1.0.8 - pathe: 2.0.3 - - plantuml-encoder@1.4.0: {} - - playwright-chromium@1.58.2: - dependencies: - playwright-core: 1.58.2 - - playwright-core@1.58.2: {} - - points-on-curve@0.2.0: {} - - points-on-path@0.2.1: - dependencies: - path-data-parser: 0.1.0 - points-on-curve: 0.2.0 - - popmotion@11.0.5: - dependencies: - framesync: 6.1.2 - hey-listen: 1.0.8 - style-value-types: 5.1.2 - tslib: 2.4.0 - - postcss-nested@7.0.2(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-parser: 7.1.1 - - postcss-selector-parser@7.1.1: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - powershell-utils@0.1.0: {} - - pptxgenjs@4.0.1: - dependencies: - '@types/node': 22.19.13 - https: 1.0.0 - image-size: 1.2.1 - jszip: 3.10.1 - - prism-theme-vars@0.2.5: {} - - process-nextick-args@2.0.1: {} - - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - - property-information@7.1.0: {} - - public-ip@8.0.0: - dependencies: - dns-socket: 4.2.2 - is-ip: 5.0.1 - - punycode.js@2.3.1: {} - - quansync@0.2.11: {} - - quansync@1.0.0: {} - - queue-microtask@1.2.3: {} - - queue@6.0.2: - dependencies: - inherits: 2.0.4 - - rc9@2.1.2: - dependencies: - defu: 6.1.4 - destr: 2.0.5 - optional: true - - rc9@3.0.0: - dependencies: - defu: 6.1.4 - destr: 2.0.5 - optional: true - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - - readdirp@5.0.0: {} - - recordrtc@5.6.2: {} - - regex-recursion@6.0.2: - dependencies: - regex-utilities: 2.3.0 - - regex-utilities@2.3.0: {} - - regex@6.1.0: - dependencies: - regex-utilities: 2.3.0 - - resolve-from@5.0.0: {} - - resolve-global@2.0.0: - dependencies: - global-directory: 4.0.1 - - reusify@1.1.0: {} - - robust-predicates@3.0.2: {} - - rollup@4.59.0: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.59.0 - '@rollup/rollup-android-arm64': 4.59.0 - '@rollup/rollup-darwin-arm64': 4.59.0 - '@rollup/rollup-darwin-x64': 4.59.0 - '@rollup/rollup-freebsd-arm64': 4.59.0 - '@rollup/rollup-freebsd-x64': 4.59.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 - '@rollup/rollup-linux-arm64-musl': 4.59.0 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 - '@rollup/rollup-linux-loong64-musl': 4.59.0 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 - '@rollup/rollup-linux-x64-gnu': 4.59.0 - '@rollup/rollup-linux-x64-musl': 4.59.0 - '@rollup/rollup-openbsd-x64': 4.59.0 - '@rollup/rollup-openharmony-arm64': 4.59.0 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 - '@rollup/rollup-win32-x64-gnu': 4.59.0 - '@rollup/rollup-win32-x64-msvc': 4.59.0 - fsevents: 2.3.3 - - roughjs@4.6.6: - dependencies: - hachure-fill: 0.5.2 - path-data-parser: 0.1.0 - points-on-curve: 0.2.0 - points-on-path: 0.2.1 - - run-applescript@7.1.0: {} - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - rw@1.3.3: {} - - safe-buffer@5.1.2: {} - - safer-buffer@2.1.2: {} - - scule@1.3.0: - optional: true - - section-matter@1.0.0: - dependencies: - extend-shallow: 2.0.1 - kind-of: 6.0.3 - - semver@6.3.1: {} - - semver@7.7.4: {} - - setimmediate@1.0.5: {} - - shiki-magic-move@1.2.1(shiki@3.23.0)(vue@3.5.29(typescript@5.9.3)): - dependencies: - diff-match-patch-es: 1.0.1 - ohash: 2.0.11 - optionalDependencies: - shiki: 3.23.0 - vue: 3.5.29(typescript@5.9.3) - - shiki@3.23.0: - dependencies: - '@shikijs/core': 3.23.0 - '@shikijs/engine-javascript': 3.23.0 - '@shikijs/engine-oniguruma': 3.23.0 - '@shikijs/langs': 3.23.0 - '@shikijs/themes': 3.23.0 - '@shikijs/types': 3.23.0 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - sirv@3.0.2: - dependencies: - '@polka/url': 1.0.0-next.29 - mrmime: 2.0.1 - totalist: 3.0.1 - - sisteransi@1.0.5: {} - - source-map-js@1.2.1: {} - - space-separated-tokens@2.0.2: {} - - sprintf-js@1.0.3: {} - - statuses@1.5.0: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@7.2.0: - dependencies: - emoji-regex: 10.6.0 - get-east-asian-width: 1.5.0 - strip-ansi: 7.2.0 - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - - stringify-entities@4.0.4: - dependencies: - character-entities-html4: 2.1.0 - character-entities-legacy: 3.0.0 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.2.2 - - strip-bom-string@1.0.0: {} - - style-value-types@5.1.2: - dependencies: - hey-listen: 1.0.8 - tslib: 2.4.0 - - stylis@4.3.6: {} - - super-regex@0.2.0: - dependencies: - clone-regexp: 3.0.0 - function-timeout: 0.1.1 - time-span: 5.1.0 - - time-span@5.1.0: - dependencies: - convert-hrtime: 5.0.0 - - tinyexec@1.0.2: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - totalist@3.0.1: {} - - trim-lines@3.0.1: {} - - ts-dedent@2.2.0: {} - - tslib@1.14.1: {} - - tslib@2.4.0: {} - - twoslash-protocol@0.3.6: {} - - twoslash-vue@0.3.6(typescript@5.9.3): - dependencies: - '@vue/language-core': 3.2.5 - twoslash: 0.3.6(typescript@5.9.3) - twoslash-protocol: 0.3.6 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - twoslash@0.3.6(typescript@5.9.3): - dependencies: - '@typescript/vfs': 1.6.4(typescript@5.9.3) - twoslash-protocol: 0.3.6 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript@5.9.3: {} - - uc.micro@2.1.0: {} - - ufo@1.6.3: {} - - unconfig-core@7.5.0: - dependencies: - '@quansync/fs': 1.0.0 - quansync: 1.0.0 - - unconfig@7.5.0: - dependencies: - '@quansync/fs': 1.0.0 - defu: 6.1.4 - jiti: 2.6.1 - quansync: 1.0.0 - unconfig-core: 7.5.0 - - unctx@2.5.0: - dependencies: - acorn: 8.16.0 - estree-walker: 3.0.3 - magic-string: 0.30.21 - unplugin: 2.3.11 - optional: true - - undici-types@6.21.0: {} - - unhead@2.1.9: - dependencies: - hookable: 6.0.1 - - unist-util-is@6.0.1: - dependencies: - '@types/unist': 3.0.3 - - unist-util-position@5.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-stringify-position@4.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-visit-parents@6.0.2: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - - unist-util-visit@5.1.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - unocss@66.6.2(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)): - dependencies: - '@unocss/cli': 66.6.2 - '@unocss/core': 66.6.2 - '@unocss/preset-attributify': 66.6.2 - '@unocss/preset-icons': 66.6.2 - '@unocss/preset-mini': 66.6.2 - '@unocss/preset-tagify': 66.6.2 - '@unocss/preset-typography': 66.6.2 - '@unocss/preset-uno': 66.6.2 - '@unocss/preset-web-fonts': 66.6.2 - '@unocss/preset-wind': 66.6.2 - '@unocss/preset-wind3': 66.6.2 - '@unocss/preset-wind4': 66.6.2 - '@unocss/transformer-attributify-jsx': 66.6.2 - '@unocss/transformer-compile-class': 66.6.2 - '@unocss/transformer-directives': 66.6.2 - '@unocss/transformer-variant-group': 66.6.2 - '@unocss/vite': 66.6.2(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - transitivePeerDependencies: - - supports-color - - vite - - unpipe@1.0.0: {} - - unplugin-icons@23.0.1(@vue/compiler-sfc@3.5.29): - dependencies: - '@antfu/install-pkg': 1.1.0 - '@iconify/utils': 3.1.0 - local-pkg: 1.1.2 - obug: 2.1.1 - unplugin: 2.3.11 - optionalDependencies: - '@vue/compiler-sfc': 3.5.29 - - unplugin-utils@0.3.1: - dependencies: - pathe: 2.0.3 - picomatch: 4.0.3 - - unplugin-vue-components@31.0.0(@nuxt/kit@3.21.1)(vue@3.5.29(typescript@5.9.3)): - dependencies: - chokidar: 5.0.0 - local-pkg: 1.1.2 - magic-string: 0.30.21 - mlly: 1.8.0 - obug: 2.1.1 - picomatch: 4.0.3 - tinyglobby: 0.2.15 - unplugin: 2.3.11 - unplugin-utils: 0.3.1 - vue: 3.5.29(typescript@5.9.3) - optionalDependencies: - '@nuxt/kit': 3.21.1 - - unplugin-vue-markdown@30.0.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)): - dependencies: - '@mdit-vue/plugin-component': 3.0.2 - '@mdit-vue/plugin-frontmatter': 3.0.2 - '@mdit-vue/types': 3.0.2 - markdown-exit: 1.0.0-beta.8 - unplugin: 2.3.11 - unplugin-utils: 0.3.1 - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - - unplugin@2.3.11: - dependencies: - '@jridgewell/remapping': 2.3.5 - acorn: 8.16.0 - picomatch: 4.0.3 - webpack-virtual-modules: 0.6.2 - - untun@0.1.3: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - pathe: 1.1.2 - - untyped@2.0.0: - dependencies: - citty: 0.1.6 - defu: 6.1.4 - jiti: 2.6.1 - knitwork: 1.3.0 - scule: 1.3.0 - optional: true - - update-browserslist-db@1.2.3(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - - uqr@0.1.2: {} - - util-deprecate@1.0.2: {} - - utils-merge@1.0.1: {} - - uuid@11.1.0: {} - - vfile-message@4.0.3: - dependencies: - '@types/unist': 3.0.3 - unist-util-stringify-position: 4.0.0 - - vfile@6.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile-message: 4.0.3 - - vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)): - dependencies: - birpc: 2.9.0 - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - vite-hot-client: 2.1.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - - vite-hot-client@2.1.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)): - dependencies: - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - - vite-plugin-inspect@11.3.3(@nuxt/kit@3.21.1)(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)): - dependencies: - ansis: 4.2.0 - debug: 4.4.3 - error-stack-parser-es: 1.0.5 - ohash: 2.0.11 - open: 10.2.0 - perfect-debounce: 2.1.0 - sirv: 3.0.2 - unplugin-utils: 0.3.1 - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)) - optionalDependencies: - '@nuxt/kit': 3.21.1 - transitivePeerDependencies: - - supports-color - - vite-plugin-remote-assets@2.1.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)): - dependencies: - debug: 4.4.3 - magic-string: 0.30.21 - node-fetch-native: 1.6.7 - ohash: 2.0.11 - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - transitivePeerDependencies: - - supports-color - - vite-plugin-static-copy@3.2.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)): - dependencies: - chokidar: 3.6.0 - p-map: 7.0.4 - picocolors: 1.1.1 - tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - - vite-plugin-vue-server-ref@1.0.0(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3)): - dependencies: - debug: 4.4.3 - klona: 2.0.6 - mlly: 1.8.0 - ufo: 1.6.3 - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - vue: 3.5.29(typescript@5.9.3) - transitivePeerDependencies: - - supports-color - - vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2): - dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.59.0 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 22.19.13 - fsevents: 2.3.3 - jiti: 2.6.1 - yaml: 2.8.2 - - vitefu@1.1.2(vite@7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2)): - optionalDependencies: - vite: 7.3.1(@types/node@22.19.13)(jiti@2.6.1)(yaml@2.8.2) - - vscode-jsonrpc@8.2.0: {} - - vscode-languageserver-protocol@3.17.5: - dependencies: - vscode-jsonrpc: 8.2.0 - vscode-languageserver-types: 3.17.5 - - vscode-languageserver-textdocument@1.0.12: {} - - vscode-languageserver-types@3.17.5: {} - - vscode-languageserver@9.0.1: - dependencies: - vscode-languageserver-protocol: 3.17.5 - - vscode-uri@3.1.0: {} - - vue-resize@2.0.0-alpha.1(vue@3.5.29(typescript@5.9.3)): - dependencies: - vue: 3.5.29(typescript@5.9.3) - - vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)): - dependencies: - '@vue/devtools-api': 6.6.4 - vue: 3.5.29(typescript@5.9.3) - - vue@3.5.29(typescript@5.9.3): - dependencies: - '@vue/compiler-dom': 3.5.29 - '@vue/compiler-sfc': 3.5.29 - '@vue/runtime-dom': 3.5.29 - '@vue/server-renderer': 3.5.29(vue@3.5.29(typescript@5.9.3)) - '@vue/shared': 3.5.29 - optionalDependencies: - typescript: 5.9.3 - - webpack-virtual-modules@0.6.2: {} - - wrap-ansi@9.0.2: - dependencies: - ansi-styles: 6.2.3 - string-width: 7.2.0 - strip-ansi: 7.2.0 - - wsl-utils@0.1.0: - dependencies: - is-wsl: 3.1.1 - - wsl-utils@0.3.1: - dependencies: - is-wsl: 3.1.1 - powershell-utils: 0.1.0 - - y18n@5.0.8: {} - - yallist@3.1.1: {} - - yaml@2.8.2: {} - - yargs-parser@22.0.0: {} - - yargs@18.0.0: - dependencies: - cliui: 9.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - string-width: 7.2.0 - y18n: 5.0.8 - yargs-parser: 22.0.0 - - zwitch@2.0.4: {} diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/0.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/0.png" deleted file mode 100644 index a762ec6..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/0.png" and /dev/null differ diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/1.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/1.png" deleted file mode 100644 index 9c10452..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/1.png" and /dev/null differ diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/2.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/2.png" deleted file mode 100644 index a19da5f..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/2.png" and /dev/null differ diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/3.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/3.png" deleted file mode 100644 index 5d8c09d..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/3.png" and /dev/null differ diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/4.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/4.png" deleted file mode 100644 index 192fedd..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/4.png" and /dev/null differ diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/5.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/5.png" deleted file mode 100644 index 21142b2..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/5.png" and /dev/null differ diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/6.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/6.png" deleted file mode 100644 index bc57699..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/6.png" and /dev/null differ diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/7.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/7.png" deleted file mode 100644 index 7623178..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/7.png" and /dev/null differ diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/8.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/8.png" deleted file mode 100644 index 18ad92e..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/8.png" and /dev/null differ diff --git "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/9.png" "b/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/9.png" deleted file mode 100644 index 0d91590..0000000 Binary files "a/slides/public/Stealth \342\200\224 Bitcoin Wallet Privacy Analyzer _ Stealth/9.png" and /dev/null differ diff --git a/slides/public/chainalysis-logo.svg b/slides/public/chainalysis-logo.svg deleted file mode 100644 index 32cfa97..0000000 --- a/slides/public/chainalysis-logo.svg +++ /dev/null @@ -1,22 +0,0 @@ - - Chainalysis logo - Chainalysis wordmark - - - - - - - - - Chainalysis - - diff --git a/slides/public/demo-2x-fast.mp4 b/slides/public/demo-2x-fast.mp4 deleted file mode 100644 index 72ae3ac..0000000 Binary files a/slides/public/demo-2x-fast.mp4 and /dev/null differ diff --git a/slides/slides.md b/slides/slides.md deleted file mode 100644 index b5594e5..0000000 --- a/slides/slides.md +++ /dev/null @@ -1,228 +0,0 @@ ---- -theme: default -title: Stealth — Bitcoin Wallet Privacy Analyzer -titleTemplate: '%s | Stealth' -class: stealth-theme -fonts: - sans: Inter - mono: JetBrains Mono -lineNumbers: false -drawings: - persist: false -transition: fade -colorSchema: dark -mdc: true ---- - -
- -

STEALTH

-

Bitcoin Wallet Privacy Analyzer

-

A read-only audit engine that surfaces wallet exposure at the UTXO level before funds move.

-
- No keys - UTXO-level findings - Self-hostable -
-
- ---- - -# The Problem -
-
-

Visibility gap

-

Bitcoin privacy leaks are invisible to users

-
    -
  • Companies like Chainalysis can analyze wallet privacy
  • -
  • Users cannot
  • -
  • People may expose: full transaction history, identity links, and behavioral fingerprints
  • -
-
-

Companies can analyze your privacy better than you can. -

-
- ---- - -# Why This Happens -
-
-

Privacy is broken by patterns, not hacks

- -Common wallet patterns that leak privacy: - -- Multi-input transactions (CIOH / consolidation) -- Combining coins -- Address reuse -- Sending change to same input address -- Dust UTXOs -- Exchange linkage / taint signals -
- ---- - -## Visibility Imbalance - -

Chainalysis users can see wallet-linkage signals that the average user cannot see about themselves.

- -
-
-
-
-
- Chainalysis -
-
-
- user -
-
-
-
- ---- - -## Privacy Parity - -

With Stealth, users gain visibility closer to institutional-grade analysis.

- -
-
-
-
-
- Chainalysis -
-
-
-
- user - STEALTH -
-
-
-
-
- ---- - -## How It Works -
-
- -
- -

01

-

Parse

-
    -
  • Input public descriptor
  • -
  • Get all addresses and UTXOs
  • -
- -
- -
- -

02

-

Fetch

-
    -
  • Load on-chain history per address
  • -
  • Use Bitcoin node
  • -
- -
- -
- -

03

-

Analyze

-
    -
  • Use privacy heuristics
  • -
  • Flag each UTXO with findings and suggestions
  • -
- -
- -
- ---- - -## Demo - -
- -

2x playback and compressed for lightweight deck rendering.

-
- ---- - -## Vulnerabilities Detected -
- - - - - - - - - - - - - - - - - - - -
Detector TypeMeaning
ADDRESS_REUSERepeated receive address links payment history
CIOHMulti-input ownership clustering signal
DUST / DUST_SPENDINGDust + normal co-spend linkage pattern
CHANGE_DETECTIONPayment and change outputs become distinguishable
CONSOLIDATION / CLUSTER_MERGEInput histories merged into one traceable cluster
SCRIPT_TYPE_MIXINGMixed script families create a wallet fingerprint
UTXO_AGE_SPREADOld/new spread leaks dormancy behavior
EXCHANGE_ORIGINProbable exchange withdrawal origin signature
TAINTED_UTXO_MERGETainted + clean merge propagates contamination
BEHAVIORAL_FINGERPRINTConsistent transaction style re-identifies wallet
- -

Warnings: DORMANT_UTXOS and DIRECT_TAINT are shown as contextual risk signals.

- ---- - -## Roadmap - -
-
-

Expanded Heuristics

-
    -
  • LEGACY_SCRIPT_EXPOSURE — old script usage (p2pkh / nested-only flows) shrinking anonymity set
  • -
  • ADDRESS_GAP_LEAK — sparse derivation usage exposing wallet generation behavior
  • -
  • AMOUNT_FINGERPRINT — repeated denomination templates across spends
  • -
  • TIME_PATTERN_FINGERPRINT — recurring timing cadence linking sessions
  • -
-
-
-

Improvements

-
    -
  • Mainnet Support

  • -
  • Mobile Support

  • -
  • Cluster Visualization

  • -
  • One-click solution
  • -
-
-
- -

Roadmap detectors are additive and keep the same read-only, no-key security model.

- ---- - -
-

Thank You

-

STEALTH

-

Bitcoin Wallet Privacy Analyzer

-

Protect privacy before you broadcast intent.

-
- diff --git a/slides/style.css b/slides/style.css deleted file mode 100644 index dbf1239..0000000 --- a/slides/style.css +++ /dev/null @@ -1,332 +0,0 @@ -/* Global Stealth deck skin */ -:root { - --slidev-theme-primary: #00d4aa; - --slidev-theme-accent: #00d4aa; - --bg: #080c14; - --surface: #0f1623; - --surface-2: #162030; - --border: #1e2d45; - --border-hover: #2a3f5e; - --accent: #00d4aa; - --accent-dim: rgba(0, 212, 170, 0.14); - --accent-glow: rgba(0, 212, 170, 0.32); - --danger: #ff4d6d; - --warning: #f4a261; - --text: #e8edf5; - --text-muted: #93a2bf; -} - -.slidev-layout { - background: - radial-gradient(1200px 500px at 90% -20%, rgba(0, 212, 170, 0.12), transparent 60%), - radial-gradient(900px 500px at -10% 110%, rgba(46, 196, 182, 0.08), transparent 60%), - var(--bg); - color: var(--text); - font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; -} - -h1, -h2, -h3 { - letter-spacing: -0.02em; -} - -h2 { - margin-bottom: 1rem; - font-size: 2.2rem; -} - -.hero-wrap { - display: grid; - gap: 0.9rem; - padding: 2.2rem; - border: 1px solid var(--border); - border-radius: 18px; - background: linear-gradient(145deg, rgba(22, 32, 48, 0.65), rgba(15, 22, 35, 0.9)); - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(0, 212, 170, 0.12) inset; -} - -.hero-wrap.end { - margin-top: 2rem; -} - -.eyebrow { - text-transform: uppercase; - letter-spacing: 0.14em; - color: var(--text-muted); - font-size: 0.72rem; - font-weight: 700; -} - -.hero-title { - font-size: 4.4rem; - line-height: 0.95; - margin: 0; -} - -.accent { - color: var(--accent); - text-shadow: 0 0 20px var(--accent-glow); -} - -.hero-subtitle { - margin: 0; - color: #c7d2e7; - font-size: 1.25rem; -} - -.hero-copy { - margin: 0; - max-width: 70ch; - color: var(--text-muted); -} - -.hero-chips { - display: flex; - gap: 0.6rem; - flex-wrap: wrap; -} - -.chip { - border: 1px solid var(--border); - border-radius: 999px; - padding: 0.2rem 0.65rem; - font-size: 0.78rem; - color: #c5d3eb; - background: rgba(22, 32, 48, 0.65); -} - -.chip-safe { - border-color: rgba(0, 212, 170, 0.32); - color: var(--accent); - background: var(--accent-dim); -} - -.split { - display: grid; - gap: 1rem; -} - -.split.two { - grid-template-columns: repeat(2, minmax(0, 1fr)); -} - -.split.three { - grid-template-columns: repeat(3, minmax(0, 1fr)); -} - -.panel { - border: 1px solid var(--border); - border-radius: 14px; - padding: 1rem; - background: linear-gradient(180deg, rgba(15, 22, 35, 0.95), rgba(13, 19, 31, 0.95)); -} - -.code-panel pre { - margin-top: 0.2rem; -} - -.kicker { - margin: 0 0 0.45rem; - text-transform: uppercase; - letter-spacing: 0.1em; - font-size: 0.7rem; - color: var(--text-muted); -} - -.strong { - margin: 0; - font-size: 1.1rem; - font-weight: 700; -} - -.muted { - margin: 0.45rem 0 0; - color: var(--text-muted); -} - -.list { - margin: 0; - padding-left: 1.1rem; - display: grid; - gap: 0.42rem; -} - -.mt { - margin-top: 1rem; -} - -.result-arrow { - margin: 0.6rem 0 0; - color: var(--accent); - font-family: 'JetBrains Mono', 'Fira Code', monospace; - font-size: 0.9rem; -} - -.detector-table { - width: 100%; - border-collapse: collapse; - border: 1px solid var(--border); - border-radius: 10px; - overflow: hidden; - background: rgba(15, 22, 35, 0.88); - font-size: 0.86rem; -} - -.detector-table th, -.detector-table td { - border-bottom: 1px solid rgba(30, 45, 69, 0.7); - padding: 0.5rem 0.62rem; - text-align: left; - vertical-align: top; -} - -.detector-table th { - color: #b6c5de; - background: rgba(22, 32, 48, 0.85); - text-transform: uppercase; - letter-spacing: 0.06em; - font-size: 0.72rem; -} - -.step-index { - font-family: 'JetBrains Mono', 'Fira Code', monospace; - color: var(--accent); - margin: 0; -} - -.flow { - margin: 0; - padding-left: 1.2rem; - display: grid; - gap: 0.55rem; -} - -.flow span { - color: var(--accent); - font-weight: 700; - margin-right: 0.3rem; -} - -.accent-panel { - border-color: rgba(0, 212, 170, 0.26); - box-shadow: 0 0 0 1px rgba(0, 212, 170, 0.1) inset; -} - -.footnote { - margin-top: 0.8rem; - color: var(--text-muted); - font-size: 0.83rem; -} - -code { - font-family: 'JetBrains Mono', 'Fira Code', monospace; -} - -/* Seesaw slide */ -.seesaw-wrap { - display: flex; - justify-content: center; - align-items: center; - min-height: 340px; - padding: 1rem; -} -.seesaw { - position: relative; - width: 100%; - max-width: 560px; -} -.seesaw-beam-bar { - position: absolute; - left: 50%; - top: 58%; - transform: translate(-50%, -50%) rotate(-14deg); - width: 90%; - height: 8px; - background: linear-gradient(90deg, var(--border), var(--border-hover), var(--border)); - border-radius: 4px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); -} -.seesaw-beam { - display: flex; - align-items: flex-start; - justify-content: center; - position: relative; - height: 180px; -} -.seesaw-pivot { - position: absolute; - left: 50%; - bottom: 0; - transform: translateX(-50%); - width: 0; - height: 0; - border-left: 14px solid transparent; - border-right: 14px solid transparent; - border-bottom: 24px solid var(--border); - z-index: 2; -} -.seesaw-side { - display: flex; - align-items: center; - justify-content: center; - flex: 1; - min-height: 96px; - padding: 0.8rem; - transition: transform 0.4s ease; -} -.seesaw-side.heavy { - transform: translateY(28px) rotate(-16deg); -} -.seesaw-side.light { - transform: translateY(-28px) rotate(16deg); -} -.chainalysis-wordmark { - font-size: 2.4rem; - font-weight: 800; - letter-spacing: -0.02em; - color: #ff6f2c; - text-shadow: 0 0 14px rgba(255, 111, 44, 0.22); -} -.user-label { - font-size: 1.4rem; - font-weight: 700; - color: var(--accent); - text-shadow: 0 0 12px var(--accent-glow); -} - -.user-stealth-stack { - display: flex; - flex-direction: column; - align-items: center; - gap: 0.25rem; -} - -.stealth-wordmark { - font-size: 1.65rem; - font-weight: 800; - letter-spacing: 0.04em; - color: var(--text); -} - -.seesaw-balanced .seesaw-beam-bar { - transform: translate(-50%, -50%) rotate(0deg); -} - -.seesaw-balanced .seesaw-side.heavy, -.seesaw-balanced .seesaw-side.light { - transform: translateY(0) rotate(0deg); -} - -/* PDF/export stability: avoid transparent gradient compositing artifacts */ -@media print { - .slidev-layout { - background: var(--bg) !important; - } - - .panel, - .hero-wrap { - background: var(--surface) !important; - box-shadow: none !important; - } -}