From 4f9919d8dd68bf8929857ac062131175aa9c3db6 Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 6 Nov 2026 19:50:23 +0000 Subject: [PATCH 01/12] Share compilation and copy independent commands and source into new worlds --- host/src/main.rs | 9 +- host/src/process/cache.rs | 340 ++++++++++++++++++++++++ host/src/process/mod.rs | 111 ++++---- host/src/world.rs | 32 ++- host/tests/p1.rs | 122 ++++++++- host/tests/process.rs | 67 ++++- userland/brush/build.nu | 6 + userland/brush/lookup.rs | 28 ++ userland/bundle.nu | 38 ++- userland/coreutils/src/bin/arch.rs | 5 + userland/coreutils/src/bin/b2sum.rs | 5 + userland/coreutils/src/bin/base32.rs | 5 + userland/coreutils/src/bin/base64.rs | 5 + userland/coreutils/src/bin/basename.rs | 5 + userland/coreutils/src/bin/basenc.rs | 5 + userland/coreutils/src/bin/cat.rs | 5 + userland/coreutils/src/bin/cksum.rs | 5 + userland/coreutils/src/bin/comm.rs | 5 + userland/coreutils/src/bin/cp.rs | 5 + userland/coreutils/src/bin/csplit.rs | 5 + userland/coreutils/src/bin/cut.rs | 5 + userland/coreutils/src/bin/date.rs | 5 + userland/coreutils/src/bin/dd.rs | 5 + userland/coreutils/src/bin/dir.rs | 5 + userland/coreutils/src/bin/dircolors.rs | 5 + userland/coreutils/src/bin/dirname.rs | 5 + userland/coreutils/src/bin/echo.rs | 5 + userland/coreutils/src/bin/expand.rs | 5 + userland/coreutils/src/bin/expr.rs | 5 + userland/coreutils/src/bin/factor.rs | 5 + userland/coreutils/src/bin/false.rs | 5 + userland/coreutils/src/bin/fmt.rs | 5 + userland/coreutils/src/bin/fold.rs | 5 + userland/coreutils/src/bin/head.rs | 5 + userland/coreutils/src/bin/hostid.rs | 5 + userland/coreutils/src/bin/join.rs | 5 + userland/coreutils/src/bin/link.rs | 5 + userland/coreutils/src/bin/ln.rs | 5 + userland/coreutils/src/bin/ls.rs | 5 + userland/coreutils/src/bin/md5sum.rs | 5 + userland/coreutils/src/bin/mkdir.rs | 5 + userland/coreutils/src/bin/mktemp.rs | 5 + userland/coreutils/src/bin/mv.rs | 5 + userland/coreutils/src/bin/nice.rs | 5 + userland/coreutils/src/bin/nl.rs | 5 + userland/coreutils/src/bin/nproc.rs | 5 + userland/coreutils/src/bin/numfmt.rs | 5 + userland/coreutils/src/bin/od.rs | 5 + userland/coreutils/src/bin/paste.rs | 5 + userland/coreutils/src/bin/pathchk.rs | 5 + userland/coreutils/src/bin/pr.rs | 5 + userland/coreutils/src/bin/printenv.rs | 5 + userland/coreutils/src/bin/printf.rs | 5 + userland/coreutils/src/bin/ptx.rs | 5 + userland/coreutils/src/bin/pwd.rs | 5 + userland/coreutils/src/bin/readlink.rs | 5 + userland/coreutils/src/bin/realpath.rs | 5 + userland/coreutils/src/bin/rm.rs | 5 + userland/coreutils/src/bin/rmdir.rs | 5 + userland/coreutils/src/bin/seq.rs | 5 + userland/coreutils/src/bin/sha1sum.rs | 5 + userland/coreutils/src/bin/sha224sum.rs | 5 + userland/coreutils/src/bin/sha256sum.rs | 5 + userland/coreutils/src/bin/sha384sum.rs | 5 + userland/coreutils/src/bin/sha512sum.rs | 5 + userland/coreutils/src/bin/shred.rs | 5 + userland/coreutils/src/bin/shuf.rs | 5 + userland/coreutils/src/bin/sleep.rs | 5 + userland/coreutils/src/bin/sort.rs | 5 + userland/coreutils/src/bin/split.rs | 5 + userland/coreutils/src/bin/sum.rs | 5 + userland/coreutils/src/bin/tail.rs | 5 + userland/coreutils/src/bin/tee.rs | 5 + userland/coreutils/src/bin/test.rs | 5 + userland/coreutils/src/bin/touch.rs | 5 + userland/coreutils/src/bin/tr.rs | 5 + userland/coreutils/src/bin/true.rs | 5 + userland/coreutils/src/bin/truncate.rs | 5 + userland/coreutils/src/bin/tsort.rs | 5 + userland/coreutils/src/bin/tty.rs | 5 + userland/coreutils/src/bin/uname.rs | 5 + userland/coreutils/src/bin/unexpand.rs | 5 + userland/coreutils/src/bin/uniq.rs | 5 + userland/coreutils/src/bin/unlink.rs | 5 + userland/coreutils/src/bin/vdir.rs | 5 + userland/coreutils/src/bin/wc.rs | 5 + userland/coreutils/src/bin/yes.rs | 5 + userland/coreutils/src/main.rs | 98 ------- userland/coreutils/tools.txt | 78 ------ userland/procps/src/main.rs | 2 +- userland/spawn/src/lib.rs | 8 +- 91 files changed, 1062 insertions(+), 267 deletions(-) create mode 100644 host/src/process/cache.rs create mode 100644 userland/brush/lookup.rs create mode 100644 userland/coreutils/src/bin/arch.rs create mode 100644 userland/coreutils/src/bin/b2sum.rs create mode 100644 userland/coreutils/src/bin/base32.rs create mode 100644 userland/coreutils/src/bin/base64.rs create mode 100644 userland/coreutils/src/bin/basename.rs create mode 100644 userland/coreutils/src/bin/basenc.rs create mode 100644 userland/coreutils/src/bin/cat.rs create mode 100644 userland/coreutils/src/bin/cksum.rs create mode 100644 userland/coreutils/src/bin/comm.rs create mode 100644 userland/coreutils/src/bin/cp.rs create mode 100644 userland/coreutils/src/bin/csplit.rs create mode 100644 userland/coreutils/src/bin/cut.rs create mode 100644 userland/coreutils/src/bin/date.rs create mode 100644 userland/coreutils/src/bin/dd.rs create mode 100644 userland/coreutils/src/bin/dir.rs create mode 100644 userland/coreutils/src/bin/dircolors.rs create mode 100644 userland/coreutils/src/bin/dirname.rs create mode 100644 userland/coreutils/src/bin/echo.rs create mode 100644 userland/coreutils/src/bin/expand.rs create mode 100644 userland/coreutils/src/bin/expr.rs create mode 100644 userland/coreutils/src/bin/factor.rs create mode 100644 userland/coreutils/src/bin/false.rs create mode 100644 userland/coreutils/src/bin/fmt.rs create mode 100644 userland/coreutils/src/bin/fold.rs create mode 100644 userland/coreutils/src/bin/head.rs create mode 100644 userland/coreutils/src/bin/hostid.rs create mode 100644 userland/coreutils/src/bin/join.rs create mode 100644 userland/coreutils/src/bin/link.rs create mode 100644 userland/coreutils/src/bin/ln.rs create mode 100644 userland/coreutils/src/bin/ls.rs create mode 100644 userland/coreutils/src/bin/md5sum.rs create mode 100644 userland/coreutils/src/bin/mkdir.rs create mode 100644 userland/coreutils/src/bin/mktemp.rs create mode 100644 userland/coreutils/src/bin/mv.rs create mode 100644 userland/coreutils/src/bin/nice.rs create mode 100644 userland/coreutils/src/bin/nl.rs create mode 100644 userland/coreutils/src/bin/nproc.rs create mode 100644 userland/coreutils/src/bin/numfmt.rs create mode 100644 userland/coreutils/src/bin/od.rs create mode 100644 userland/coreutils/src/bin/paste.rs create mode 100644 userland/coreutils/src/bin/pathchk.rs create mode 100644 userland/coreutils/src/bin/pr.rs create mode 100644 userland/coreutils/src/bin/printenv.rs create mode 100644 userland/coreutils/src/bin/printf.rs create mode 100644 userland/coreutils/src/bin/ptx.rs create mode 100644 userland/coreutils/src/bin/pwd.rs create mode 100644 userland/coreutils/src/bin/readlink.rs create mode 100644 userland/coreutils/src/bin/realpath.rs create mode 100644 userland/coreutils/src/bin/rm.rs create mode 100644 userland/coreutils/src/bin/rmdir.rs create mode 100644 userland/coreutils/src/bin/seq.rs create mode 100644 userland/coreutils/src/bin/sha1sum.rs create mode 100644 userland/coreutils/src/bin/sha224sum.rs create mode 100644 userland/coreutils/src/bin/sha256sum.rs create mode 100644 userland/coreutils/src/bin/sha384sum.rs create mode 100644 userland/coreutils/src/bin/sha512sum.rs create mode 100644 userland/coreutils/src/bin/shred.rs create mode 100644 userland/coreutils/src/bin/shuf.rs create mode 100644 userland/coreutils/src/bin/sleep.rs create mode 100644 userland/coreutils/src/bin/sort.rs create mode 100644 userland/coreutils/src/bin/split.rs create mode 100644 userland/coreutils/src/bin/sum.rs create mode 100644 userland/coreutils/src/bin/tail.rs create mode 100644 userland/coreutils/src/bin/tee.rs create mode 100644 userland/coreutils/src/bin/test.rs create mode 100644 userland/coreutils/src/bin/touch.rs create mode 100644 userland/coreutils/src/bin/tr.rs create mode 100644 userland/coreutils/src/bin/true.rs create mode 100644 userland/coreutils/src/bin/truncate.rs create mode 100644 userland/coreutils/src/bin/tsort.rs create mode 100644 userland/coreutils/src/bin/tty.rs create mode 100644 userland/coreutils/src/bin/uname.rs create mode 100644 userland/coreutils/src/bin/unexpand.rs create mode 100644 userland/coreutils/src/bin/uniq.rs create mode 100644 userland/coreutils/src/bin/unlink.rs create mode 100644 userland/coreutils/src/bin/vdir.rs create mode 100644 userland/coreutils/src/bin/wc.rs create mode 100644 userland/coreutils/src/bin/yes.rs delete mode 100644 userland/coreutils/src/main.rs delete mode 100644 userland/coreutils/tools.txt diff --git a/host/src/main.rs b/host/src/main.rs index 44866a0..879e293 100644 --- a/host/src/main.rs +++ b/host/src/main.rs @@ -5,6 +5,9 @@ use std::path::PathBuf; #[derive(Parser)] #[command(version, about)] struct Cli { + /// Shared host-user compile cache (otherwise SAUSAGE_CACHE or the XDG cache folder). + #[arg(long, global = true)] + cache: Option, #[command(subcommand)] command: Command, } @@ -29,7 +32,11 @@ enum Command { #[tokio::main] async fn main() -> anyhow::Result<()> { - match Cli::parse().command { + let cli = Cli::parse(); + if let Some(cache) = cli.cache { + sausage::process::configure_cache(cache)?; + } + match cli.command { Command::Run { world, userland } => { let bundle = userland.or_else(|| std::env::var_os("SAUSAGE_USERLAND").map(PathBuf::from)); diff --git a/host/src/process/cache.rs b/host/src/process/cache.rs new file mode 100644 index 0000000..972feea --- /dev/null +++ b/host/src/process/cache.rs @@ -0,0 +1,340 @@ +//! Shares compiled programs and single-flight compilation across worlds in one host process. +use super::{Compiled, State, adapter, bindings}; +use std::{ + collections::HashMap, + path::{Path, PathBuf}, + sync::{Arc, Mutex, OnceLock}, +}; +use tokio::sync::watch; +type Compilation = watch::Receiver>>; +use wasmtime::{ + Engine, + component::{Component, Linker}, +}; +use wasmtime_wasi::p2::bindings::CommandPre; + +static DIRECTORY: OnceLock = OnceLock::new(); +static SHARED: Mutex>> = Mutex::new(None); + +/// Select the host user's cache before opening a world. +pub fn configure(directory: PathBuf) -> anyhow::Result<()> { + DIRECTORY + .set(directory) + .map_err(|_| anyhow::anyhow!("cache directory already configured")) +} +fn directory() -> anyhow::Result { + if let Some(dir) = DIRECTORY.get() { + return Ok(dir.clone()); + } + if let Some(dir) = std::env::var_os("SAUSAGE_CACHE") { + return Ok(dir.into()); + } + if let Some(dir) = std::env::var_os("XDG_CACHE_HOME") { + return Ok(PathBuf::from(dir).join("sausage")); + } + Ok( + PathBuf::from(std::env::var_os("HOME").ok_or_else(|| anyhow::anyhow!("HOME is not set"))?) + .join(".cache/sausage"), + ) +} +pub(super) fn shared() -> anyhow::Result> { + let mut shared = SHARED.lock().unwrap(); + if shared.is_none() { + *shared = Some(Compiler::new(&directory()?)?); + } + Ok(shared.as_ref().unwrap().clone()) +} +pub(super) struct Compiler { + pub engine: Engine, + programs: Mutex, Compilation>>, + #[cfg(test)] + before_compile: Mutex>>, + #[cfg(test)] + compilations: std::sync::atomic::AtomicUsize, +} +impl Compiler { + pub fn new(directory: &Path) -> anyhow::Result> { + Self::with_opt(directory, wasmtime::OptLevel::Speed) + } + fn with_opt(directory: &Path, opt: wasmtime::OptLevel) -> anyhow::Result> { + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + let mut config = wasmtime::Config::new(); + config.epoch_interruption(true); + config.cranelift_opt_level(opt); + let mut cache = wasmtime::CacheConfig::new(); + cache.with_directory(directory); + config.cache(Some(wasmtime::Cache::new(cache)?)); + Ok(Arc::new(Self { + engine: Engine::new(&config)?, + programs: Mutex::new(HashMap::new()), + #[cfg(test)] + before_compile: Mutex::new(None), + #[cfg(test)] + compilations: std::sync::atomic::AtomicUsize::new(0), + })) + } + pub async fn get(self: &Arc, bytes: Vec) -> anyhow::Result { + let mut result = self + .programs + .lock() + .unwrap() + .entry(bytes.clone()) + .or_insert_with(|| { + let (tx, rx) = watch::channel(None); + let compiler = self.clone(); + // The job owns completion even if a command or a precompile waiter is cancelled. + tokio::spawn(async move { + let result = + tokio::task::spawn_blocking(move || compiler.compile(&bytes)).await; + tx.send_replace(Some( + result + .map_err(anyhow::Error::from) + .and_then(|r| r) + .map_err(|e| format!("{e:#}")), + )); + }); + rx + }) + .clone(); + loop { + if let Some(result) = result.borrow().clone() { + return result.map_err(|e| anyhow::anyhow!(e)); + } + result.changed().await?; + } + } + fn compile(&self, bytes: &[u8]) -> anyhow::Result { + #[cfg(test)] + { + self.compilations + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + if let Some(hook) = self.before_compile.lock().unwrap().take() { + hook(); + } + } + if bytes.get(..8) == Some(b"\0asm\x01\0\0\0") { + let module = wasmtime::Module::new(&self.engine, bytes)?; + let mut linker = wasmtime::Linker::new(&self.engine); + sausage_vfs::preview1::add_to_linker(&mut linker, |s: &mut State| { + s.preview1.as_mut().unwrap() + })?; + Ok(Compiled::Module(linker.instantiate_pre(&module)?)) + } else { + let component = Component::new(&self.engine, bytes)?; + let mut linker = Linker::new(&self.engine); + wasmtime_wasi::p2::add_to_linker_async(&mut linker)?; + wasmtime_wasi_http::p2::add_only_http_to_linker_async(&mut linker)?; + adapter::add_to_linker(&mut linker, |s: &mut State| adapter::View { + adapter: &mut s.fs, + table: &mut s.table, + })?; + bindings::sausage::process::host::add_to_linker::<_, wasmtime::component::HasSelf<_>>( + &mut linker, + |s| s, + )?; + Ok(Compiled::Component(CommandPre::new( + linker.instantiate_pre(&component)?, + )?)) + } + } +} +/// Compile programs in both command folders without blocking world startup. +pub(super) fn precompile( + compiler: Arc, + root: Arc, +) -> tokio::task::JoinHandle> { + tokio::spawn(async move { + let mut tasks = tokio::task::JoinSet::new(); + for folder in ["/bin", "/usr/local/bin"] { + let entries = match root.list(folder).await { + Ok(entries) => entries, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => continue, + Err(e) => return Err(e.into()), + }; + for entry in entries.into_iter().filter(|entry| !entry.directory) { + let root = root.clone(); + let compiler = compiler.clone(); + let path = format!("{folder}/{}", entry.name); + tasks.spawn(async move { + let file = root + .open( + &path, + sausage_vfs::Open { + follow: true, + ..Default::default() + }, + ) + .await?; + let bytes = file.read(0, file.stat().await?.size as usize).await?; + if bytes.get(..4) != Some(b"\0asm") { + return Ok::<_, anyhow::Error>(false); + } + compiler.get(bytes).await?; + Ok(true) + }); + } + } + let mut count = 0; + while let Some(result) = tasks.join_next().await { + if result?? { + count += 1; + } + } + Ok(count) + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::exec::{Command, Exec, Options}; + use std::{future::Future, sync::atomic::Ordering}; + + #[tokio::test(flavor = "multi_thread")] + #[ignore = "Temporary T15 timing probe; remove before review"] + async fn measure_world() { + let bundle = Path::new(env!("CARGO_MANIFEST_DIR")).join("../target/userland/bundle"); + let temp = tempfile::tempdir().unwrap(); + for (index, script) in ["echo hi | tr a-z A-Z", "git --version", "rg --version"] + .into_iter() + .enumerate() + { + let cache = temp.path().join(format!("cache-{index}")); + let start = std::time::Instant::now(); + let world = crate::world::World::open_with_userland( + &temp.path().join(format!("cold-{index}")), + Some(&bundle), + ) + .unwrap(); + let runtime = super::super::Runtime::new_with_cache(world, &cache).unwrap(); + let mut output = |_: crate::exec::Stream, _: &[u8]| {}; + assert_eq!( + runtime + .exec( + Command::Shell(script.into()), + Options::default(), + &mut output + ) + .await + .unwrap(), + 0 + ); + println!( + "profile={} state=cold command={script:?} seconds={:.6}", + if cfg!(debug_assertions) { + "debug" + } else { + "release" + }, + start.elapsed().as_secs_f64() + ); + let count = runtime.precompile().await.unwrap().unwrap(); + println!( + "background commands={count} seconds={:.6}", + start.elapsed().as_secs_f64() + ); + let start = std::time::Instant::now(); + assert_eq!( + runtime + .exec( + Command::Shell(script.into()), + Options::default(), + &mut output + ) + .await + .unwrap(), + 0 + ); + println!( + "state=same-host command={script:?} seconds={:.6}", + start.elapsed().as_secs_f64() + ); + drop(runtime); + let start = std::time::Instant::now(); + let world = crate::world::World::open_with_userland( + &temp.path().join(format!("warm-{index}")), + Some(&bundle), + ) + .unwrap(); + let runtime = super::super::Runtime::new_with_cache(world, &cache).unwrap(); + assert_eq!( + runtime + .exec( + Command::Shell(script.into()), + Options::default(), + &mut output + ) + .await + .unwrap(), + 0 + ); + println!( + "state=fresh-warm command={script:?} seconds={:.6}", + start.elapsed().as_secs_f64() + ); + runtime.precompile().await.unwrap().unwrap(); + } + } + + #[test] + #[ignore = "Temporary T15 timing probe; remove before review"] + fn measure_optimizer() { + let bundle = Path::new(env!("CARGO_MANIFEST_DIR")).join("../target/userland/bundle/bin"); + let temp = tempfile::tempdir().unwrap(); + for opt in [wasmtime::OptLevel::Speed, wasmtime::OptLevel::None] { + let compiler = Compiler::with_opt(&temp.path().join(format!("{opt:?}")), opt).unwrap(); + for name in ["sh", "tr", "git", "rg"] { + let bytes = std::fs::read(bundle.join(format!("{name}.wasm"))).unwrap(); + let start = std::time::Instant::now(); + compiler.compile(&bytes).unwrap(); + println!( + "optimizer={opt:?} program={name} bytes={} compile_seconds={:.6}", + bytes.len(), + start.elapsed().as_secs_f64() + ); + } + } + } + + #[tokio::test(flavor = "multi_thread")] + async fn command_joins_precompile_even_after_waiter_cancellation() { + let temp = tempfile::tempdir().unwrap(); + let compiler = Compiler::new(&temp.path().join("cache")).unwrap(); + let world = crate::world::World::open(&temp.path().join("world")).unwrap(); + let bytes = + wat::parse_str(r#"(module (memory (export "memory") 1) (func (export "_start")))"#) + .unwrap(); + std::fs::create_dir_all(temp.path().join("world/world/bin")).unwrap(); + std::fs::write(temp.path().join("world/world/bin/program.wasm"), &bytes).unwrap(); + let (started_tx, started_rx) = tokio::sync::oneshot::channel(); + let (finish_tx, finish_rx) = std::sync::mpsc::channel(); + *compiler.before_compile.lock().unwrap() = Some(Box::new(move || { + started_tx.send(()).unwrap(); + finish_rx.recv().unwrap(); + })); + // Startup returns while the compiler remains blocked behind the test gate. + let runtime = super::super::Runtime::with_compiler(world, compiler.clone()).unwrap(); + started_rx.await.unwrap(); + let background = compiler.clone(); + let precompile = tokio::spawn(async move { background.get(bytes).await }); + let mut output = |_: crate::exec::Stream, _: &[u8]| {}; + let command = runtime.exec( + Command::Argv(vec!["/bin/program".into()]), + Options::default(), + &mut output, + ); + tokio::pin!(command); + let pending = std::future::poll_fn(|cx| { + std::task::Poll::Ready(command.as_mut().poll(cx).is_pending()) + }) + .await; + assert!(pending); + assert_eq!(compiler.compilations.load(Ordering::Relaxed), 1); + precompile.abort(); + let _ = precompile.await; + finish_tx.send(()).unwrap(); + assert_eq!(command.await.unwrap(), 0); + assert_eq!(compiler.compilations.load(Ordering::Relaxed), 1); + assert!(!temp.path().join("world/host/compile-cache").exists()); + } +} diff --git a/host/src/process/mod.rs b/host/src/process/mod.rs index 187c423..fd525e8 100644 --- a/host/src/process/mod.rs +++ b/host/src/process/mod.rs @@ -5,7 +5,7 @@ use crate::{ }; use sausage_vfs::{ Mounts, - adapter::{self, Adapter, View}, + adapter::{self, Adapter}, }; use std::{ collections::HashMap, @@ -22,7 +22,7 @@ use tokio::{ }; use wasmtime::{ Engine, Store, - component::{Component, Linker, Resource, ResourceTable}, + component::{Resource, ResourceTable}, }; use wasmtime_wasi::{ WasiCtx, WasiCtxBuilder, WasiCtxView, WasiView, @@ -45,6 +45,8 @@ mod bindings { }); } use bindings::sausage::process::host::{Host, HostChild, Request, Stdio}; +mod cache; +pub use cache::configure as configure_cache; mod services; mod stdio; pub use services::supervise; @@ -77,7 +79,8 @@ struct Entry { pub struct Runtime { world: World, engine: Engine, - cache: Mutex, Compiled>>, + compiler: Arc, + cache: Mutex>>, entries: Mutex>, next: AtomicU32, alive: Arc, @@ -138,14 +141,14 @@ impl Runtime { Self::new(World::open(path)?) } pub fn new(world: World) -> anyhow::Result> { - // Deno and WASI HTTP enable different providers. Select one before HTTPS creates a client. - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); - let mut config = wasmtime::Config::new(); - config.epoch_interruption(true); - let mut cache = wasmtime::CacheConfig::new(); - cache.with_directory(world.host_dir.join("compile-cache")); - config.cache(Some(wasmtime::Cache::new(cache)?)); - let engine = Engine::new(&config)?; + Self::with_compiler(world, cache::shared()?) + } + /// Open an independent engine using an explicit shared disk cache. + pub fn new_with_cache(world: World, directory: &Path) -> anyhow::Result> { + Self::with_compiler(world, cache::Compiler::new(directory)?) + } + fn with_compiler(world: World, compiler: Arc) -> anyhow::Result> { + let engine = compiler.engine.clone(); let alive = Arc::new(AtomicBool::new(true)); let ticking = alive.clone(); let clock = engine.clone(); @@ -155,19 +158,61 @@ impl Runtime { clock.increment_epoch(); } }); - Ok(Arc::new(Self { + let runtime = Arc::new(Self { world, engine, alive, - cache: Mutex::new(HashMap::new()), + compiler, + cache: Mutex::new(Default::default()), entries: Mutex::new(HashMap::new()), next: AtomicU32::new(1), - })) + }); + runtime.precompile(); + Ok(runtime) + } + /// Join startup precompilation of both command folders through the shared content slots. + pub fn precompile(&self) -> tokio::task::JoinHandle> { + cache::precompile(self.compiler.clone(), self.world.root.clone()) } /// Number of distinct program contents compiled by this runtime. pub fn compiled_programs(&self) -> usize { self.cache.lock().unwrap().len() } + async fn resolve_program( + &self, + cwd: &str, + name: &str, + env: &[(String, String)], + ) -> anyhow::Result { + let paths = if name.contains('/') { + vec![sausage_vfs::resolve(cwd, name)] + } else { + let path = env + .iter() + .find(|(key, _)| key == "PATH") + .map(|(_, value)| value.as_str()) + .unwrap_or("/usr/local/bin:/bin"); + path.split(':') + .map(|folder| { + sausage_vfs::resolve( + cwd, + &std::path::Path::new(folder).join(name).to_string_lossy(), + ) + }) + .collect() + }; + for path in paths { + for candidate in [path.clone(), format!("{path}.wasm")] { + match self.world.root.stat(&candidate, true).await { + Ok(stat) if !stat.directory => return Ok(candidate), + Ok(_) => {} + Err(e) if e.kind() == std::io::ErrorKind::NotFound => {} + Err(e) => return Err(e.into()), + } + } + } + anyhow::bail!("program not found: {name}") + } fn kill_command(&self, command: u32) { for entry in self.entries.lock().unwrap().values() { if entry.command == command { @@ -222,7 +267,9 @@ impl Runtime { request.cwd = sausage_vfs::resolve("/", &request.cwd); request.env.retain(|(name, _)| name != "PWD"); request.env.push(("PWD".into(), request.cwd.clone())); - let executable = sausage_vfs::resolve(&request.cwd, &request.program); + let executable = self + .resolve_program(&request.cwd, &request.program, &request.env) + .await?; let file = self .world .root @@ -237,38 +284,8 @@ impl Runtime { let bytes = file .read(0, usize::try_from(file.stat().await?.size)?) .await?; - let pre = { - let mut cache = self.cache.lock().unwrap(); - if let Some(pre) = cache.get(&bytes) { - pre.clone() - } else { - let pre = if bytes.get(..8) == Some(b"\0asm\x01\0\0\0") { - let module = wasmtime::Module::new(&self.engine, &bytes)?; - let mut linker = wasmtime::Linker::new(&self.engine); - sausage_vfs::preview1::add_to_linker(&mut linker, |s: &mut State| { - s.preview1.as_mut().unwrap() - })?; - Compiled::Module(linker.instantiate_pre(&module)?) - } else { - let component = Component::new(&self.engine, &bytes)?; - let mut linker = Linker::new(&self.engine); - wasmtime_wasi::p2::add_to_linker_async(&mut linker)?; - // The library linker includes exit-with-code. Only Wasmtime's CLI gates it. - wasmtime_wasi_http::p2::add_only_http_to_linker_async(&mut linker)?; - adapter::add_to_linker(&mut linker, |s: &mut State| View { - adapter: &mut s.fs, - table: &mut s.table, - })?; - bindings::sausage::process::host::add_to_linker::< - _, - wasmtime::component::HasSelf<_>, - >(&mut linker, |s| s)?; - Compiled::Component(CommandPre::new(linker.instantiate_pre(&component)?)?) - }; - cache.insert(bytes, pre.clone()); - pre - } - }; + let pre = self.compiler.get(bytes.clone()).await?; + self.cache.lock().unwrap().insert(bytes); let pid = self.next.fetch_add(1, Ordering::Relaxed); let command = if command == 0 { pid } else { command }; let group = match request.group { diff --git a/host/src/world.rs b/host/src/world.rs index 0185b1f..b77674e 100644 --- a/host/src/world.rs +++ b/host/src/world.rs @@ -19,17 +19,37 @@ pub struct World { pub processes: crate::process::Processes, } +fn copy_tree(source: &Path, destination: &Path) -> std::io::Result<()> { + std::fs::create_dir_all(destination)?; + for entry in std::fs::read_dir(source)? { + let entry = entry?; + let target = destination.join(entry.file_name()); + if entry.file_type()?.is_dir() { + copy_tree(&entry.path(), &target)?; + } else { + std::fs::copy(entry.path(), target)?; + } + } + Ok(()) +} + impl World { /// Open (and create if missing) the world directory `dir`, including `/proc` and `/run` mounts. pub fn open(dir: &Path) -> anyhow::Result { Self::open_with_userland(dir, None) } - /// Mount an optional host bundle read-only at `/bin` (D43). + /// Copy an optional bundle into a new world. Existing worlds retain their programs. pub fn open_with_userland(dir: &Path, userland: Option<&Path>) -> anyhow::Result { let root_dir = dir.join("world"); let host_dir = dir.join("host"); + let fresh = !root_dir.exists(); std::fs::create_dir_all(root_dir.join("usr/local/bin"))?; + if fresh && let Some(bundle) = userland { + for folder in ["bin", "src"] { + copy_tree(&bundle.join(folder), &root_dir.join(folder))?; + } + } std::fs::create_dir_all(&host_dir)?; let mut mounts = Mounts::default(); mounts.mount( @@ -55,17 +75,11 @@ impl World { } Ok(text.into_bytes()) }); - if let Some(bundle) = userland { - mounts.mount( - "/bin", - Arc::new(Host::new(bundle, Process::default())?), - true, - ); - } mounts.mount("/proc", Arc::new(proc), true); mounts.mount("/run", Arc::new(Memory::default()), false); + let root: Arc = Arc::new(mounts); Ok(World { - root: Arc::new(mounts), + root, host_dir, processes, }) diff --git a/host/tests/p1.rs b/host/tests/p1.rs index ade9671..65fd7f9 100644 --- a/host/tests/p1.rs +++ b/host/tests/p1.rs @@ -1,13 +1,13 @@ -//! P1 integration: a read-only bundle and real shell calls from the durable harness. +//! P1 integration: independent bundle copies and real shell calls from the durable harness. use sausage::{harness::run_module, world::World}; use sausage_vfs::Open; use std::path::PathBuf; #[tokio::test(flavor = "current_thread")] -async fn bundle_mount_and_real_shell() -> anyhow::Result<()> { +async fn bundle_copy_and_real_shell() -> anyhow::Result<()> { let repo = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(".."); - let bundle = repo.join("target/userland/bin"); - if !bundle.join("sh").exists() { + let bundle = repo.join("target/userland/bundle"); + if !bundle.join("bin/sh.wasm").exists() { assert!( std::process::Command::new("nu") .env_remove("CARGO_TARGET_DIR") @@ -18,9 +18,16 @@ async fn bundle_mount_and_real_shell() -> anyhow::Result<()> { } let dir = tempfile::tempdir()?; let world = World::open_with_userland(dir.path(), Some(&bundle))?; - assert!(world.root.stat("/bin/sh", true).await?.size > 0); + assert!(world.root.stat("/bin/sh.wasm", true).await?.size > 0); + use std::os::unix::fs::MetadataExt; + for entry in std::fs::read_dir(dir.path().join("world/bin"))? { + let entry = entry?; + assert_eq!(entry.path().extension().unwrap(), "wasm"); + assert_eq!(entry.metadata()?.nlink(), 1); + assert!(!entry.file_type()?.is_symlink()); + } assert!(world.root.stat("/usr/local/bin", true).await?.directory); - let denied = world + let writable = world .root .open( "/bin/forbidden", @@ -31,17 +38,72 @@ async fn bundle_mount_and_real_shell() -> anyhow::Result<()> { }, ) .await; - assert!(matches!(denied, Err(e) if e.kind() == std::io::ErrorKind::ReadOnlyFilesystem)); + assert!(writable.is_ok()); let exec = sausage::process::exec(World { root: world.root.clone(), host_dir: world.host_dir.clone(), processes: world.processes.clone(), })?; + use sausage::exec::{Command, Options, Stream}; + for (script, expected) in [ + ("command -v ls", "/bin/ls.wasm\n"), + ("ls", "bin"), + ("git --version", "git version"), + ("printf 'a\\n' | xargs echo", "a\n"), + ("env FOO=1 printenv FOO", "1\n"), + ] { + let mut out = Vec::new(); + let code = exec + .exec( + Command::Shell(script.into()), + Options::default(), + &mut |stream, bytes| { + if matches!(stream, Stream::Stdout) { + out.extend_from_slice(bytes); + } + }, + ) + .await?; + assert_eq!(code, 0, "{script}"); + assert!(String::from_utf8(out)?.contains(expected), "{script}"); + } + let mut history = Vec::new(); + assert_eq!( + exec.exec( + Command::Shell("cd /src/sausage && git log --oneline".into()), + Options::default(), + &mut |stream, bytes| { + if matches!(stream, Stream::Stdout) { + history.extend_from_slice(bytes); + } + }, + ) + .await?, + 0, + ); + let history = String::from_utf8(history)?; + assert_eq!(history.lines().count(), 1); + assert!(history.contains("Bundle source ")); + let mut status = Vec::new(); + assert_eq!( + exec.exec( + Command::Shell("cd /src/sausage && git status --short".into()), + Options::default(), + &mut |stream, bytes| { + if matches!(stream, Stream::Stdout) { + status.extend_from_slice(bytes); + } + }, + ) + .await?, + 0, + ); + assert!(status.is_empty(), "{}", String::from_utf8_lossy(&status)); let source = format!( "globalThis.testP1 = true;\n{}", include_str!("../js/test-bundle.js") ); - run_module(world, exec, &source).await?; + run_module(world, exec.clone(), &source).await?; assert_eq!( std::fs::read_to_string(dir.path().join("world/test.txt"))?, "after\n" @@ -59,6 +121,50 @@ async fn bundle_mount_and_real_shell() -> anyhow::Result<()> { let actual = std::fs::read_to_string(spills[0].path())?; let expected: String = (1..=10000).map(|n| format!("{n}\n")).collect(); assert_eq!(actual, expected); + let source_cat = std::fs::read(bundle.join("bin/cat.wasm"))?; + let head = std::fs::read(dir.path().join("world/bin/head.wasm"))?; + let mut out = Vec::new(); + assert_eq!( + exec.exec( + Command::Shell( + "cp /bin/true.wasm /bin/cat.wasm; cat /test.txt; head -n 1 /test.txt".into() + ), + Options::default(), + &mut |stream, bytes| { + if matches!(stream, Stream::Stdout) { + out.extend_from_slice(bytes); + } + } + ) + .await?, + 0 + ); + assert_eq!(out, b"after\n"); + assert_eq!(std::fs::read(bundle.join("bin/cat.wasm"))?, source_cat); + assert_eq!(std::fs::read(dir.path().join("world/bin/head.wasm"))?, head); + assert_eq!( + exec.exec( + Command::Shell("cp /bin/true.wasm /usr/local/bin/head.wasm; head /test.txt".into()), + Options::default(), + &mut |_, bytes| assert!(bytes.is_empty()) + ) + .await?, + 0 + ); + let changed = std::fs::read(dir.path().join("world/bin/cat.wasm"))?; + let reopened = World::open_with_userland( + dir.path(), + Some(std::path::Path::new("/nonexistent-bundle")), + )?; + assert_eq!( + reopened + .root + .open("/bin/cat.wasm", Open::default()) + .await? + .read(0, changed.len()) + .await?, + changed + ); // An unbundled world remains usable by process tests and file-only callers. let unbundled = tempfile::tempdir()?; let world = World::open(unbundled.path())?; diff --git a/host/tests/process.rs b/host/tests/process.rs index 3332f75..d980b7a 100644 --- a/host/tests/process.rs +++ b/host/tests/process.rs @@ -9,6 +9,39 @@ use std::{ sync::{Arc, Once}, time::Duration, }; +#[test] +fn world_copies_programs_and_nested_source_only_once() -> anyhow::Result<()> { + let temp = tempfile::tempdir()?; + let bundle = temp.path().join("bundle"); + std::fs::create_dir_all(bundle.join("bin"))?; + std::fs::create_dir_all(bundle.join("src/sausage/.git"))?; + std::fs::write(bundle.join("bin/probe.wasm"), b"program")?; + std::fs::write( + bundle.join("src/sausage/.git/HEAD"), + b"ref: refs/heads/main\n", + )?; + std::fs::write(bundle.join("src/sausage/README.md"), b"source")?; + let path = temp.path().join("world"); + let _world = World::open_with_userland(&path, Some(&bundle))?; + assert_eq!( + std::fs::read(path.join("world/bin/probe.wasm"))?, + b"program" + ); + assert_eq!( + std::fs::read(path.join("world/src/sausage/README.md"))?, + b"source" + ); + assert!(path.join("world/src/sausage/.git/HEAD").is_file()); + std::fs::write(path.join("world/src/sausage/README.md"), b"agent patch")?; + let _world = World::open_with_userland(&path, Some(Path::new("/missing-bundle")))?; + assert_eq!( + std::fs::read(path.join("world/src/sausage/README.md"))?, + b"agent patch" + ); + assert!(!path.join("host/compile-cache").exists()); + Ok(()) +} + mod features { //! Acceptance coverage for preview1, identity, inherited IO, services, HTTP, and bundle aliases. use super::*; @@ -260,28 +293,32 @@ mod features { empty(&processes).await; } #[tokio::test(flavor = "multi_thread")] - async fn relative_aliases_share_compilation() { + async fn independent_copies_share_compilation() { let _serial = SERIAL.lock().await; let (temp, runtime, _) = world(); let bin = temp.path().join("world/bin"); - for name in ["true", "echo"] { - std::os::unix::fs::symlink("cat", bin.join(name)).unwrap(); + for name in ["read-a.wasm", "read-b.wasm"] { + std::fs::copy(bin.join("cat.wasm"), bin.join(name)).unwrap(); } assert_eq!( - run(&runtime, Command::Argv(vec!["/bin/true".into()]), "/") - .await - .0, + run( + &runtime, + Command::Argv(vec!["/bin/read-a".into(), "/f".into()]), + "/" + ) + .await + .0, 0 ); assert_eq!(runtime.compiled_programs(), 1); let (code, out, _) = run( &runtime, - Command::Argv(vec!["/bin/echo".into(), "shared".into()]), + Command::Argv(vec!["/bin/read-b".into(), "/f".into()]), "/", ) .await; assert_eq!(code, 0); - assert_eq!(out, b"shared\n"); + assert_eq!(out, b"root\n"); assert_eq!(runtime.compiled_programs(), 1); } #[tokio::test(flavor = "multi_thread")] @@ -464,13 +501,17 @@ fn world() -> (tempfile::TempDir, Arc, sausage::process::Processes) { let world = World::open(temp.path()).unwrap(); let cache = Path::new(env!("CARGO_TARGET_TMPDIR")).join("process-host/compile-cache"); std::fs::create_dir_all(&cache).unwrap(); - std::os::unix::fs::symlink(cache, world.host_dir.join("compile-cache")).unwrap(); + let processes = world.processes.clone(); fixture(&temp.path().join("world")); let artifacts = repo().join("userland/target/wasm32-wasip2/release"); let bin = temp.path().join("world/bin"); for tool in ["cat", "tr", "ls", "wc", "yes", "head", "sleep"] { - std::fs::copy(artifacts.join("sausage-coreutils.wasm"), bin.join(tool)).unwrap(); + std::fs::copy( + artifacts.join(format!("{tool}.wasm")), + bin.join(format!("{tool}.wasm")), + ) + .unwrap(); } for tool in ["ps", "kill"] { std::fs::copy(artifacts.join("sausage-procps.wasm"), bin.join(tool)).unwrap(); @@ -491,7 +532,11 @@ fn world() -> (tempfile::TempDir, Arc, sausage::process::Processes) { bin.join("git"), ) .unwrap(); - (temp, Runtime::new(world).unwrap(), processes) + ( + temp, + Runtime::new_with_cache(world, &cache).unwrap(), + processes, + ) } async fn run(runtime: &Arc, command: Command, cwd: &str) -> (i32, Vec, Vec) { let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); diff --git a/userland/brush/build.nu b/userland/brush/build.nu index 46213f3..da7908b 100644 --- a/userland/brush/build.nu +++ b/userland/brush/build.nu @@ -18,6 +18,12 @@ def main [] { if (^git -C $source rev-parse HEAD | str trim) != $revision { error make {msg: 'unexpected brush revision'} } let core = ($source | path join brush-core) copy-if-changed ($here | path join process.rs) ($core | path join src sys wasm process.rs) + copy-if-changed ($here | path join lookup.rs) ($core | path join src sys wasm sausage-lookup.rs) + let fs = ($core | path join src sys wasm fs.rs) + let fs_text = (open --raw $fs) + if not ($fs_text | str contains 'include!("sausage-lookup.rs")') { + $fs_text + "\ninclude!(\"sausage-lookup.rs\");\n" | save --force $fs + } mkdir ($core | path join sausage-process) let wit = ($here | path join .. .. host wit | path expand) copy-if-changed ($wit | path join process.wit) ($core | path join sausage-process process.wit) diff --git a/userland/brush/lookup.rs b/userland/brush/lookup.rs new file mode 100644 index 0000000..260f3f8 --- /dev/null +++ b/userland/brush/lookup.rs @@ -0,0 +1,28 @@ +/// Resolve ordinary files before the WASI suffix in each PATH folder. +pub fn resolve_executable(path: std::path::PathBuf) -> Option { + if path.is_file() { + return Some(path); + } + let mut name = path.into_os_string(); + name.push(".wasm"); + let path = std::path::PathBuf::from(name); + path.is_file().then_some(path) +} +pub(crate) fn resolve_executable_path( + path: std::path::PathBuf, + working_dir: &std::path::Path, +) -> std::path::PathBuf { + let absolute = working_dir.join(&path); + if absolute.is_file() { + return path; + } + let mut name = absolute.into_os_string(); + name.push(".wasm"); + if std::path::PathBuf::from(name).is_file() { + let mut name = path.into_os_string(); + name.push(".wasm"); + name.into() + } else { + path + } +} diff --git a/userland/bundle.nu b/userland/bundle.nu index fa8e28b..f743b15 100644 --- a/userland/bundle.nu +++ b/userland/bundle.nu @@ -1,8 +1,9 @@ #!/usr/bin/env nu -# Build every workspace CLI and assemble the read-only /bin bundle. +# Build independent commands and a committed source snapshot of their repository. def main [destination?: path] { let here = $env.FILE_PWD - let destination = ($destination | default ($here | path join .. target userland bin) | path expand) + let destination = ($destination | default ($here | path join .. target userland bundle) | path expand) + let bin = ($destination | path join bin) let object = ($here | path join cwd-init init.o) let sources = [($here | path join cwd-init init.rs) ($here | path join cwd-init exit.wit) ($here | path join cwd-init build.nu)] if not ($object | path exists) or ($sources | any {|source| (ls $source | get modified.0) > (ls $object | get modified.0) }) { @@ -14,23 +15,46 @@ def main [destination?: path] { if $env.LAST_EXIT_CODE != 0 { error make {msg: 'userland build failed'} } ^nu ($here | path join brush build.nu) if $env.LAST_EXIT_CODE != 0 { error make {msg: 'brush build failed'} } - mkdir $destination + mkdir $bin for package in ($metadata.packages | where {|p| $p.id in $metadata.workspace_members }) { let tools = ($package.manifest_path | path dirname | path join tools.txt) for binary in ($package.targets | where {|t| 'bin' in $t.kind }) { let source = ($metadata.target_directory | path join wasm32-wasip2 release $'($binary.name).wasm') let names = if ($tools | path exists) { open --raw $tools | lines | where {|s| ($s | str trim) != '' } } else { [$binary.name] } for name in $names { - ^ln -f $source ($destination | path join $name) - if $env.LAST_EXIT_CODE != 0 { error make {msg: $'bundle link failed: ($name)'} } + ^cp --remove-destination $source ($bin | path join $'($name).wasm') + if $env.LAST_EXIT_CODE != 0 { error make {msg: $'bundle copy failed: ($name)'} } } } } let brush_metadata = (^cargo metadata --manifest-path ($here | path join brush source Cargo.toml) --no-deps --format-version 1 | from json) let brush = ($brush_metadata.target_directory | path join wasm32-wasip2 release brush.wasm) for name in [sh bash] { - ^ln -f $brush ($destination | path join $name) - if $env.LAST_EXIT_CODE != 0 { error make {msg: 'brush link failed'} } + ^cp --remove-destination $brush ($bin | path join $'($name).wasm') + if $env.LAST_EXIT_CODE != 0 { error make {msg: 'brush copy failed'} } + } + let repo = ($here | path join .. | path expand) + let revision = (^git -C $repo rev-parse HEAD | str trim) + let snapshot = ($destination | path join src sausage) + if ($snapshot | path exists) { rm --recursive --force $snapshot } + mkdir $snapshot + let archive = ($destination | path join source.tar) + ^git -C $repo archive --output $archive HEAD host vfs userland Cargo.toml Cargo.lock flake.nix flake.lock README.md AGENTS.md .gitignore + if $env.LAST_EXIT_CODE != 0 { error make {msg: 'source archive failed'} } + ^tar -xf $archive -C $snapshot + if $env.LAST_EXIT_CODE != 0 { error make {msg: 'source extraction failed'} } + rm $archive + ^git -C $snapshot init --quiet --initial-branch=main + if $env.LAST_EXIT_CODE != 0 { error make {msg: 'source git init failed'} } + ^git -C $snapshot add host vfs userland Cargo.toml Cargo.lock flake.nix flake.lock README.md AGENTS.md .gitignore + if $env.LAST_EXIT_CODE != 0 { error make {msg: 'source git add failed'} } + with-env { + GIT_AUTHOR_NAME: 'Sausage', GIT_AUTHOR_EMAIL: 'sausage@localhost', + GIT_COMMITTER_NAME: 'Sausage', GIT_COMMITTER_EMAIL: 'sausage@localhost', + GIT_AUTHOR_DATE: '2000-01-01T00:00:00+0000', GIT_COMMITTER_DATE: '2000-01-01T00:00:00+0000' + } { + ^git -C $snapshot commit --no-gpg-sign --quiet -m $'Bundle source ($revision)' + if $env.LAST_EXIT_CODE != 0 { error make {msg: 'source git commit failed'} } } print $destination } diff --git a/userland/coreutils/src/bin/arch.rs b/userland/coreutils/src/bin/arch.rs new file mode 100644 index 0000000..f682a17 --- /dev/null +++ b/userland/coreutils/src/bin/arch.rs @@ -0,0 +1,5 @@ +//! Implements the arch command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("arch").expect("utility supplies localization"); + std::process::exit(uu_arch::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/b2sum.rs b/userland/coreutils/src/bin/b2sum.rs new file mode 100644 index 0000000..d21bbd5 --- /dev/null +++ b/userland/coreutils/src/bin/b2sum.rs @@ -0,0 +1,5 @@ +//! Implements the b2sum command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("b2sum").expect("utility supplies localization"); + std::process::exit(uu_b2sum::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/base32.rs b/userland/coreutils/src/bin/base32.rs new file mode 100644 index 0000000..4a0c434 --- /dev/null +++ b/userland/coreutils/src/bin/base32.rs @@ -0,0 +1,5 @@ +//! Implements the base32 command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("base32").expect("utility supplies localization"); + std::process::exit(uu_base32::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/base64.rs b/userland/coreutils/src/bin/base64.rs new file mode 100644 index 0000000..79e0ce9 --- /dev/null +++ b/userland/coreutils/src/bin/base64.rs @@ -0,0 +1,5 @@ +//! Implements the base64 command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("base64").expect("utility supplies localization"); + std::process::exit(uu_base64::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/basename.rs b/userland/coreutils/src/bin/basename.rs new file mode 100644 index 0000000..234fc0a --- /dev/null +++ b/userland/coreutils/src/bin/basename.rs @@ -0,0 +1,5 @@ +//! Implements the basename command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("basename").expect("utility supplies localization"); + std::process::exit(uu_basename::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/basenc.rs b/userland/coreutils/src/bin/basenc.rs new file mode 100644 index 0000000..05c22fb --- /dev/null +++ b/userland/coreutils/src/bin/basenc.rs @@ -0,0 +1,5 @@ +//! Implements the basenc command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("basenc").expect("utility supplies localization"); + std::process::exit(uu_basenc::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/cat.rs b/userland/coreutils/src/bin/cat.rs new file mode 100644 index 0000000..0f4ff1b --- /dev/null +++ b/userland/coreutils/src/bin/cat.rs @@ -0,0 +1,5 @@ +//! Implements the cat command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("cat").expect("utility supplies localization"); + std::process::exit(uu_cat::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/cksum.rs b/userland/coreutils/src/bin/cksum.rs new file mode 100644 index 0000000..58294cd --- /dev/null +++ b/userland/coreutils/src/bin/cksum.rs @@ -0,0 +1,5 @@ +//! Implements the cksum command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("cksum").expect("utility supplies localization"); + std::process::exit(uu_cksum::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/comm.rs b/userland/coreutils/src/bin/comm.rs new file mode 100644 index 0000000..51ef1e5 --- /dev/null +++ b/userland/coreutils/src/bin/comm.rs @@ -0,0 +1,5 @@ +//! Implements the comm command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("comm").expect("utility supplies localization"); + std::process::exit(uu_comm::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/cp.rs b/userland/coreutils/src/bin/cp.rs new file mode 100644 index 0000000..c320dd0 --- /dev/null +++ b/userland/coreutils/src/bin/cp.rs @@ -0,0 +1,5 @@ +//! Implements the cp command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("cp").expect("utility supplies localization"); + std::process::exit(uu_cp::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/csplit.rs b/userland/coreutils/src/bin/csplit.rs new file mode 100644 index 0000000..8d24215 --- /dev/null +++ b/userland/coreutils/src/bin/csplit.rs @@ -0,0 +1,5 @@ +//! Implements the csplit command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("csplit").expect("utility supplies localization"); + std::process::exit(uu_csplit::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/cut.rs b/userland/coreutils/src/bin/cut.rs new file mode 100644 index 0000000..bc1dbf4 --- /dev/null +++ b/userland/coreutils/src/bin/cut.rs @@ -0,0 +1,5 @@ +//! Implements the cut command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("cut").expect("utility supplies localization"); + std::process::exit(uu_cut::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/date.rs b/userland/coreutils/src/bin/date.rs new file mode 100644 index 0000000..7f95526 --- /dev/null +++ b/userland/coreutils/src/bin/date.rs @@ -0,0 +1,5 @@ +//! Implements the date command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("date").expect("utility supplies localization"); + std::process::exit(uu_date::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/dd.rs b/userland/coreutils/src/bin/dd.rs new file mode 100644 index 0000000..1475ca2 --- /dev/null +++ b/userland/coreutils/src/bin/dd.rs @@ -0,0 +1,5 @@ +//! Implements the dd command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("dd").expect("utility supplies localization"); + std::process::exit(uu_dd::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/dir.rs b/userland/coreutils/src/bin/dir.rs new file mode 100644 index 0000000..76c0d22 --- /dev/null +++ b/userland/coreutils/src/bin/dir.rs @@ -0,0 +1,5 @@ +//! Implements the dir command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("ls").expect("utility supplies localization"); + std::process::exit(uu_dir::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/dircolors.rs b/userland/coreutils/src/bin/dircolors.rs new file mode 100644 index 0000000..aaa7527 --- /dev/null +++ b/userland/coreutils/src/bin/dircolors.rs @@ -0,0 +1,5 @@ +//! Implements the dircolors command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("dircolors").expect("utility supplies localization"); + std::process::exit(uu_dircolors::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/dirname.rs b/userland/coreutils/src/bin/dirname.rs new file mode 100644 index 0000000..3fe4ff4 --- /dev/null +++ b/userland/coreutils/src/bin/dirname.rs @@ -0,0 +1,5 @@ +//! Implements the dirname command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("dirname").expect("utility supplies localization"); + std::process::exit(uu_dirname::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/echo.rs b/userland/coreutils/src/bin/echo.rs new file mode 100644 index 0000000..dd479b5 --- /dev/null +++ b/userland/coreutils/src/bin/echo.rs @@ -0,0 +1,5 @@ +//! Implements the echo command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("echo").expect("utility supplies localization"); + std::process::exit(uu_echo::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/expand.rs b/userland/coreutils/src/bin/expand.rs new file mode 100644 index 0000000..3e0b0ca --- /dev/null +++ b/userland/coreutils/src/bin/expand.rs @@ -0,0 +1,5 @@ +//! Implements the expand command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("expand").expect("utility supplies localization"); + std::process::exit(uu_expand::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/expr.rs b/userland/coreutils/src/bin/expr.rs new file mode 100644 index 0000000..001ec55 --- /dev/null +++ b/userland/coreutils/src/bin/expr.rs @@ -0,0 +1,5 @@ +//! Implements the expr command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("expr").expect("utility supplies localization"); + std::process::exit(uu_expr::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/factor.rs b/userland/coreutils/src/bin/factor.rs new file mode 100644 index 0000000..71cd796 --- /dev/null +++ b/userland/coreutils/src/bin/factor.rs @@ -0,0 +1,5 @@ +//! Implements the factor command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("factor").expect("utility supplies localization"); + std::process::exit(uu_factor::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/false.rs b/userland/coreutils/src/bin/false.rs new file mode 100644 index 0000000..cf3a464 --- /dev/null +++ b/userland/coreutils/src/bin/false.rs @@ -0,0 +1,5 @@ +//! Implements the false command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("false").expect("utility supplies localization"); + std::process::exit(uu_false::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/fmt.rs b/userland/coreutils/src/bin/fmt.rs new file mode 100644 index 0000000..ad6d2ac --- /dev/null +++ b/userland/coreutils/src/bin/fmt.rs @@ -0,0 +1,5 @@ +//! Implements the fmt command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("fmt").expect("utility supplies localization"); + std::process::exit(uu_fmt::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/fold.rs b/userland/coreutils/src/bin/fold.rs new file mode 100644 index 0000000..caa0eb5 --- /dev/null +++ b/userland/coreutils/src/bin/fold.rs @@ -0,0 +1,5 @@ +//! Implements the fold command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("fold").expect("utility supplies localization"); + std::process::exit(uu_fold::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/head.rs b/userland/coreutils/src/bin/head.rs new file mode 100644 index 0000000..eb0fbf4 --- /dev/null +++ b/userland/coreutils/src/bin/head.rs @@ -0,0 +1,5 @@ +//! Implements the head command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("head").expect("utility supplies localization"); + std::process::exit(uu_head::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/hostid.rs b/userland/coreutils/src/bin/hostid.rs new file mode 100644 index 0000000..4966820 --- /dev/null +++ b/userland/coreutils/src/bin/hostid.rs @@ -0,0 +1,5 @@ +//! Implements the hostid command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("hostid").expect("utility supplies localization"); + std::process::exit(uu_hostid::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/join.rs b/userland/coreutils/src/bin/join.rs new file mode 100644 index 0000000..3831cc4 --- /dev/null +++ b/userland/coreutils/src/bin/join.rs @@ -0,0 +1,5 @@ +//! Implements the join command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("join").expect("utility supplies localization"); + std::process::exit(uu_join::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/link.rs b/userland/coreutils/src/bin/link.rs new file mode 100644 index 0000000..956480f --- /dev/null +++ b/userland/coreutils/src/bin/link.rs @@ -0,0 +1,5 @@ +//! Implements the link command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("link").expect("utility supplies localization"); + std::process::exit(uu_link::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/ln.rs b/userland/coreutils/src/bin/ln.rs new file mode 100644 index 0000000..c893121 --- /dev/null +++ b/userland/coreutils/src/bin/ln.rs @@ -0,0 +1,5 @@ +//! Implements the ln command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("ln").expect("utility supplies localization"); + std::process::exit(uu_ln::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/ls.rs b/userland/coreutils/src/bin/ls.rs new file mode 100644 index 0000000..5545e9e --- /dev/null +++ b/userland/coreutils/src/bin/ls.rs @@ -0,0 +1,5 @@ +//! Implements the ls command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("ls").expect("utility supplies localization"); + std::process::exit(uu_ls::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/md5sum.rs b/userland/coreutils/src/bin/md5sum.rs new file mode 100644 index 0000000..735797e --- /dev/null +++ b/userland/coreutils/src/bin/md5sum.rs @@ -0,0 +1,5 @@ +//! Implements the md5sum command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("md5sum").expect("utility supplies localization"); + std::process::exit(uu_md5sum::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/mkdir.rs b/userland/coreutils/src/bin/mkdir.rs new file mode 100644 index 0000000..c2f8923 --- /dev/null +++ b/userland/coreutils/src/bin/mkdir.rs @@ -0,0 +1,5 @@ +//! Implements the mkdir command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("mkdir").expect("utility supplies localization"); + std::process::exit(uu_mkdir::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/mktemp.rs b/userland/coreutils/src/bin/mktemp.rs new file mode 100644 index 0000000..71e0781 --- /dev/null +++ b/userland/coreutils/src/bin/mktemp.rs @@ -0,0 +1,5 @@ +//! Implements the mktemp command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("mktemp").expect("utility supplies localization"); + std::process::exit(uu_mktemp::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/mv.rs b/userland/coreutils/src/bin/mv.rs new file mode 100644 index 0000000..f62bfb1 --- /dev/null +++ b/userland/coreutils/src/bin/mv.rs @@ -0,0 +1,5 @@ +//! Implements the mv command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("mv").expect("utility supplies localization"); + std::process::exit(uu_mv::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/nice.rs b/userland/coreutils/src/bin/nice.rs new file mode 100644 index 0000000..b31f52d --- /dev/null +++ b/userland/coreutils/src/bin/nice.rs @@ -0,0 +1,5 @@ +//! Implements the nice command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("nice").expect("utility supplies localization"); + std::process::exit(uu_nice::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/nl.rs b/userland/coreutils/src/bin/nl.rs new file mode 100644 index 0000000..0a50d3c --- /dev/null +++ b/userland/coreutils/src/bin/nl.rs @@ -0,0 +1,5 @@ +//! Implements the nl command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("nl").expect("utility supplies localization"); + std::process::exit(uu_nl::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/nproc.rs b/userland/coreutils/src/bin/nproc.rs new file mode 100644 index 0000000..fcc81f2 --- /dev/null +++ b/userland/coreutils/src/bin/nproc.rs @@ -0,0 +1,5 @@ +//! Implements the nproc command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("nproc").expect("utility supplies localization"); + std::process::exit(uu_nproc::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/numfmt.rs b/userland/coreutils/src/bin/numfmt.rs new file mode 100644 index 0000000..07829ae --- /dev/null +++ b/userland/coreutils/src/bin/numfmt.rs @@ -0,0 +1,5 @@ +//! Implements the numfmt command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("numfmt").expect("utility supplies localization"); + std::process::exit(uu_numfmt::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/od.rs b/userland/coreutils/src/bin/od.rs new file mode 100644 index 0000000..cab0501 --- /dev/null +++ b/userland/coreutils/src/bin/od.rs @@ -0,0 +1,5 @@ +//! Implements the od command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("od").expect("utility supplies localization"); + std::process::exit(uu_od::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/paste.rs b/userland/coreutils/src/bin/paste.rs new file mode 100644 index 0000000..17559db --- /dev/null +++ b/userland/coreutils/src/bin/paste.rs @@ -0,0 +1,5 @@ +//! Implements the paste command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("paste").expect("utility supplies localization"); + std::process::exit(uu_paste::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/pathchk.rs b/userland/coreutils/src/bin/pathchk.rs new file mode 100644 index 0000000..0a919d9 --- /dev/null +++ b/userland/coreutils/src/bin/pathchk.rs @@ -0,0 +1,5 @@ +//! Implements the pathchk command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("pathchk").expect("utility supplies localization"); + std::process::exit(uu_pathchk::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/pr.rs b/userland/coreutils/src/bin/pr.rs new file mode 100644 index 0000000..0ca52d0 --- /dev/null +++ b/userland/coreutils/src/bin/pr.rs @@ -0,0 +1,5 @@ +//! Implements the pr command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("pr").expect("utility supplies localization"); + std::process::exit(uu_pr::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/printenv.rs b/userland/coreutils/src/bin/printenv.rs new file mode 100644 index 0000000..a3f3800 --- /dev/null +++ b/userland/coreutils/src/bin/printenv.rs @@ -0,0 +1,5 @@ +//! Implements the printenv command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("printenv").expect("utility supplies localization"); + std::process::exit(uu_printenv::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/printf.rs b/userland/coreutils/src/bin/printf.rs new file mode 100644 index 0000000..720c8a7 --- /dev/null +++ b/userland/coreutils/src/bin/printf.rs @@ -0,0 +1,5 @@ +//! Implements the printf command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("printf").expect("utility supplies localization"); + std::process::exit(uu_printf::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/ptx.rs b/userland/coreutils/src/bin/ptx.rs new file mode 100644 index 0000000..a5d7fa7 --- /dev/null +++ b/userland/coreutils/src/bin/ptx.rs @@ -0,0 +1,5 @@ +//! Implements the ptx command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("ptx").expect("utility supplies localization"); + std::process::exit(uu_ptx::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/pwd.rs b/userland/coreutils/src/bin/pwd.rs new file mode 100644 index 0000000..c62049f --- /dev/null +++ b/userland/coreutils/src/bin/pwd.rs @@ -0,0 +1,5 @@ +//! Implements the pwd command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("pwd").expect("utility supplies localization"); + std::process::exit(uu_pwd::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/readlink.rs b/userland/coreutils/src/bin/readlink.rs new file mode 100644 index 0000000..5fb109b --- /dev/null +++ b/userland/coreutils/src/bin/readlink.rs @@ -0,0 +1,5 @@ +//! Implements the readlink command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("readlink").expect("utility supplies localization"); + std::process::exit(uu_readlink::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/realpath.rs b/userland/coreutils/src/bin/realpath.rs new file mode 100644 index 0000000..fb4e428 --- /dev/null +++ b/userland/coreutils/src/bin/realpath.rs @@ -0,0 +1,5 @@ +//! Implements the realpath command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("realpath").expect("utility supplies localization"); + std::process::exit(uu_realpath::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/rm.rs b/userland/coreutils/src/bin/rm.rs new file mode 100644 index 0000000..f1a3549 --- /dev/null +++ b/userland/coreutils/src/bin/rm.rs @@ -0,0 +1,5 @@ +//! Implements the rm command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("rm").expect("utility supplies localization"); + std::process::exit(uu_rm::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/rmdir.rs b/userland/coreutils/src/bin/rmdir.rs new file mode 100644 index 0000000..ee5edc1 --- /dev/null +++ b/userland/coreutils/src/bin/rmdir.rs @@ -0,0 +1,5 @@ +//! Implements the rmdir command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("rmdir").expect("utility supplies localization"); + std::process::exit(uu_rmdir::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/seq.rs b/userland/coreutils/src/bin/seq.rs new file mode 100644 index 0000000..b6ed06d --- /dev/null +++ b/userland/coreutils/src/bin/seq.rs @@ -0,0 +1,5 @@ +//! Implements the seq command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("seq").expect("utility supplies localization"); + std::process::exit(uu_seq::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/sha1sum.rs b/userland/coreutils/src/bin/sha1sum.rs new file mode 100644 index 0000000..c601c6e --- /dev/null +++ b/userland/coreutils/src/bin/sha1sum.rs @@ -0,0 +1,5 @@ +//! Implements the sha1sum command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("sha1sum").expect("utility supplies localization"); + std::process::exit(uu_sha1sum::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/sha224sum.rs b/userland/coreutils/src/bin/sha224sum.rs new file mode 100644 index 0000000..96be305 --- /dev/null +++ b/userland/coreutils/src/bin/sha224sum.rs @@ -0,0 +1,5 @@ +//! Implements the sha224sum command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("sha224sum").expect("utility supplies localization"); + std::process::exit(uu_sha224sum::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/sha256sum.rs b/userland/coreutils/src/bin/sha256sum.rs new file mode 100644 index 0000000..d8935f8 --- /dev/null +++ b/userland/coreutils/src/bin/sha256sum.rs @@ -0,0 +1,5 @@ +//! Implements the sha256sum command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("sha256sum").expect("utility supplies localization"); + std::process::exit(uu_sha256sum::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/sha384sum.rs b/userland/coreutils/src/bin/sha384sum.rs new file mode 100644 index 0000000..8897db2 --- /dev/null +++ b/userland/coreutils/src/bin/sha384sum.rs @@ -0,0 +1,5 @@ +//! Implements the sha384sum command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("sha384sum").expect("utility supplies localization"); + std::process::exit(uu_sha384sum::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/sha512sum.rs b/userland/coreutils/src/bin/sha512sum.rs new file mode 100644 index 0000000..2cdcc6e --- /dev/null +++ b/userland/coreutils/src/bin/sha512sum.rs @@ -0,0 +1,5 @@ +//! Implements the sha512sum command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("sha512sum").expect("utility supplies localization"); + std::process::exit(uu_sha512sum::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/shred.rs b/userland/coreutils/src/bin/shred.rs new file mode 100644 index 0000000..55b5aa8 --- /dev/null +++ b/userland/coreutils/src/bin/shred.rs @@ -0,0 +1,5 @@ +//! Implements the shred command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("shred").expect("utility supplies localization"); + std::process::exit(uu_shred::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/shuf.rs b/userland/coreutils/src/bin/shuf.rs new file mode 100644 index 0000000..641ee63 --- /dev/null +++ b/userland/coreutils/src/bin/shuf.rs @@ -0,0 +1,5 @@ +//! Implements the shuf command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("shuf").expect("utility supplies localization"); + std::process::exit(uu_shuf::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/sleep.rs b/userland/coreutils/src/bin/sleep.rs new file mode 100644 index 0000000..0ab1a97 --- /dev/null +++ b/userland/coreutils/src/bin/sleep.rs @@ -0,0 +1,5 @@ +//! Implements the sleep command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("sleep").expect("utility supplies localization"); + std::process::exit(uu_sleep::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/sort.rs b/userland/coreutils/src/bin/sort.rs new file mode 100644 index 0000000..c89f40e --- /dev/null +++ b/userland/coreutils/src/bin/sort.rs @@ -0,0 +1,5 @@ +//! Implements the sort command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("sort").expect("utility supplies localization"); + std::process::exit(uu_sort::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/split.rs b/userland/coreutils/src/bin/split.rs new file mode 100644 index 0000000..737e83f --- /dev/null +++ b/userland/coreutils/src/bin/split.rs @@ -0,0 +1,5 @@ +//! Implements the split command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("split").expect("utility supplies localization"); + std::process::exit(uu_split::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/sum.rs b/userland/coreutils/src/bin/sum.rs new file mode 100644 index 0000000..9b80e68 --- /dev/null +++ b/userland/coreutils/src/bin/sum.rs @@ -0,0 +1,5 @@ +//! Implements the sum command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("sum").expect("utility supplies localization"); + std::process::exit(uu_sum::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/tail.rs b/userland/coreutils/src/bin/tail.rs new file mode 100644 index 0000000..b497795 --- /dev/null +++ b/userland/coreutils/src/bin/tail.rs @@ -0,0 +1,5 @@ +//! Implements the tail command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("tail").expect("utility supplies localization"); + std::process::exit(uu_tail::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/tee.rs b/userland/coreutils/src/bin/tee.rs new file mode 100644 index 0000000..42bae96 --- /dev/null +++ b/userland/coreutils/src/bin/tee.rs @@ -0,0 +1,5 @@ +//! Implements the tee command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("tee").expect("utility supplies localization"); + std::process::exit(uu_tee::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/test.rs b/userland/coreutils/src/bin/test.rs new file mode 100644 index 0000000..8a9f8f4 --- /dev/null +++ b/userland/coreutils/src/bin/test.rs @@ -0,0 +1,5 @@ +//! Implements the test command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("test").expect("utility supplies localization"); + std::process::exit(uu_test::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/touch.rs b/userland/coreutils/src/bin/touch.rs new file mode 100644 index 0000000..d81624a --- /dev/null +++ b/userland/coreutils/src/bin/touch.rs @@ -0,0 +1,5 @@ +//! Implements the touch command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("touch").expect("utility supplies localization"); + std::process::exit(uu_touch::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/tr.rs b/userland/coreutils/src/bin/tr.rs new file mode 100644 index 0000000..ddf2acb --- /dev/null +++ b/userland/coreutils/src/bin/tr.rs @@ -0,0 +1,5 @@ +//! Implements the tr command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("tr").expect("utility supplies localization"); + std::process::exit(uu_tr::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/true.rs b/userland/coreutils/src/bin/true.rs new file mode 100644 index 0000000..63979b6 --- /dev/null +++ b/userland/coreutils/src/bin/true.rs @@ -0,0 +1,5 @@ +//! Implements the true command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("true").expect("utility supplies localization"); + std::process::exit(uu_true::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/truncate.rs b/userland/coreutils/src/bin/truncate.rs new file mode 100644 index 0000000..5bca57f --- /dev/null +++ b/userland/coreutils/src/bin/truncate.rs @@ -0,0 +1,5 @@ +//! Implements the truncate command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("truncate").expect("utility supplies localization"); + std::process::exit(uu_truncate::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/tsort.rs b/userland/coreutils/src/bin/tsort.rs new file mode 100644 index 0000000..7babdb8 --- /dev/null +++ b/userland/coreutils/src/bin/tsort.rs @@ -0,0 +1,5 @@ +//! Implements the tsort command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("tsort").expect("utility supplies localization"); + std::process::exit(uu_tsort::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/tty.rs b/userland/coreutils/src/bin/tty.rs new file mode 100644 index 0000000..aeab75f --- /dev/null +++ b/userland/coreutils/src/bin/tty.rs @@ -0,0 +1,5 @@ +//! Implements the tty command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("tty").expect("utility supplies localization"); + std::process::exit(uu_tty::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/uname.rs b/userland/coreutils/src/bin/uname.rs new file mode 100644 index 0000000..a8c8953 --- /dev/null +++ b/userland/coreutils/src/bin/uname.rs @@ -0,0 +1,5 @@ +//! Implements the uname command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("uname").expect("utility supplies localization"); + std::process::exit(uu_uname::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/unexpand.rs b/userland/coreutils/src/bin/unexpand.rs new file mode 100644 index 0000000..7753075 --- /dev/null +++ b/userland/coreutils/src/bin/unexpand.rs @@ -0,0 +1,5 @@ +//! Implements the unexpand command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("unexpand").expect("utility supplies localization"); + std::process::exit(uu_unexpand::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/uniq.rs b/userland/coreutils/src/bin/uniq.rs new file mode 100644 index 0000000..5891b29 --- /dev/null +++ b/userland/coreutils/src/bin/uniq.rs @@ -0,0 +1,5 @@ +//! Implements the uniq command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("uniq").expect("utility supplies localization"); + std::process::exit(uu_uniq::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/unlink.rs b/userland/coreutils/src/bin/unlink.rs new file mode 100644 index 0000000..0249957 --- /dev/null +++ b/userland/coreutils/src/bin/unlink.rs @@ -0,0 +1,5 @@ +//! Implements the unlink command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("unlink").expect("utility supplies localization"); + std::process::exit(uu_unlink::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/vdir.rs b/userland/coreutils/src/bin/vdir.rs new file mode 100644 index 0000000..c3b426d --- /dev/null +++ b/userland/coreutils/src/bin/vdir.rs @@ -0,0 +1,5 @@ +//! Implements the vdir command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("ls").expect("utility supplies localization"); + std::process::exit(uu_vdir::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/wc.rs b/userland/coreutils/src/bin/wc.rs new file mode 100644 index 0000000..b866eaf --- /dev/null +++ b/userland/coreutils/src/bin/wc.rs @@ -0,0 +1,5 @@ +//! Implements the wc command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("wc").expect("utility supplies localization"); + std::process::exit(uu_wc::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/bin/yes.rs b/userland/coreutils/src/bin/yes.rs new file mode 100644 index 0000000..ac14fcf --- /dev/null +++ b/userland/coreutils/src/bin/yes.rs @@ -0,0 +1,5 @@ +//! Implements the yes command as an independent WASI binary. +fn main() { + uucore::locale::setup_localization("yes").expect("utility supplies localization"); + std::process::exit(uu_yes::uumain(uucore::args_os())); +} \ No newline at end of file diff --git a/userland/coreutils/src/main.rs b/userland/coreutils/src/main.rs deleted file mode 100644 index c77947d..0000000 --- a/userland/coreutils/src/main.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Dispatches the portable uutils 0.12 multicall component by argv[0]. -fn main() { - let argv0 = std::env::args().next().unwrap(); - let name = std::path::Path::new(&argv0) - .file_name() - .unwrap() - .to_str() - .unwrap(); - let name = if name == "[" { "test" } else { name }; - let locale = match name { - "dir" | "vdir" => "ls", - _ => name, - }; - uucore::locale::setup_localization(locale).expect("utility supplies localization"); - let args = uucore::args_os(); - let code = match name { - "arch" => uu_arch::uumain(args), - "base32" => uu_base32::uumain(args), - "base64" => uu_base64::uumain(args), - "basename" => uu_basename::uumain(args), - "basenc" => uu_basenc::uumain(args), - "cat" => uu_cat::uumain(args), - "cksum" => uu_cksum::uumain(args), - "b2sum" => uu_b2sum::uumain(args), - "md5sum" => uu_md5sum::uumain(args), - "nice" => uu_nice::uumain(args), - "sha1sum" => uu_sha1sum::uumain(args), - "sha224sum" => uu_sha224sum::uumain(args), - "sha256sum" => uu_sha256sum::uumain(args), - "sha384sum" => uu_sha384sum::uumain(args), - "sha512sum" => uu_sha512sum::uumain(args), - "comm" => uu_comm::uumain(args), - "cp" => uu_cp::uumain(args), - "csplit" => uu_csplit::uumain(args), - "cut" => uu_cut::uumain(args), - "date" => uu_date::uumain(args), - "dd" => uu_dd::uumain(args), - "dir" => uu_dir::uumain(args), - "dircolors" => uu_dircolors::uumain(args), - "dirname" => uu_dirname::uumain(args), - "echo" => uu_echo::uumain(args), - "expand" => uu_expand::uumain(args), - "expr" => uu_expr::uumain(args), - "factor" => uu_factor::uumain(args), - "false" => uu_false::uumain(args), - "fmt" => uu_fmt::uumain(args), - "fold" => uu_fold::uumain(args), - "head" => uu_head::uumain(args), - "hostid" => uu_hostid::uumain(args), - "join" => uu_join::uumain(args), - "link" => uu_link::uumain(args), - "ln" => uu_ln::uumain(args), - "ls" => uu_ls::uumain(args), - "mkdir" => uu_mkdir::uumain(args), - "mktemp" => uu_mktemp::uumain(args), - "mv" => uu_mv::uumain(args), - "nl" => uu_nl::uumain(args), - "numfmt" => uu_numfmt::uumain(args), - "od" => uu_od::uumain(args), - "paste" => uu_paste::uumain(args), - "pathchk" => uu_pathchk::uumain(args), - "pr" => uu_pr::uumain(args), - "printenv" => uu_printenv::uumain(args), - "printf" => uu_printf::uumain(args), - "ptx" => uu_ptx::uumain(args), - "pwd" => uu_pwd::uumain(args), - "readlink" => uu_readlink::uumain(args), - "realpath" => uu_realpath::uumain(args), - "rm" => uu_rm::uumain(args), - "rmdir" => uu_rmdir::uumain(args), - "seq" => uu_seq::uumain(args), - "shred" => uu_shred::uumain(args), - "shuf" => uu_shuf::uumain(args), - "sleep" => uu_sleep::uumain(args), - "sort" => uu_sort::uumain(args), - "split" => uu_split::uumain(args), - "sum" => uu_sum::uumain(args), - "tail" => uu_tail::uumain(args), - "tee" => uu_tee::uumain(args), - "test" => uu_test::uumain(args), - "touch" => uu_touch::uumain(args), - "tr" => uu_tr::uumain(args), - "true" => uu_true::uumain(args), - "truncate" => uu_truncate::uumain(args), - "tsort" => uu_tsort::uumain(args), - "tty" => uu_tty::uumain(args), - "uname" => uu_uname::uumain(args), - "unexpand" => uu_unexpand::uumain(args), - "uniq" => uu_uniq::uumain(args), - "unlink" => uu_unlink::uumain(args), - "vdir" => uu_vdir::uumain(args), - "wc" => uu_wc::uumain(args), - "yes" => uu_yes::uumain(args), - "nproc" => uu_nproc::uumain(args), - _ => 127, - }; - std::process::exit(code); -} diff --git a/userland/coreutils/tools.txt b/userland/coreutils/tools.txt deleted file mode 100644 index a57aa31..0000000 --- a/userland/coreutils/tools.txt +++ /dev/null @@ -1,78 +0,0 @@ -arch -base32 -base64 -basename -basenc -cat -cksum -b2sum -md5sum -nice -sha1sum -sha224sum -sha256sum -sha384sum -sha512sum -comm -cp -csplit -cut -date -dd -dir -dircolors -dirname -echo -expand -expr -factor -false -fmt -fold -head -hostid -join -link -ln -ls -mkdir -mktemp -mv -nl -numfmt -od -paste -pathchk -pr -printenv -printf -ptx -pwd -readlink -realpath -rm -rmdir -seq -shred -shuf -sleep -sort -split -sum -tail -tee -test -touch -tr -true -truncate -tsort -tty -uname -unexpand -uniq -unlink -vdir -wc -yes -nproc diff --git a/userland/procps/src/main.rs b/userland/procps/src/main.rs index 4ebe58c..c783b03 100644 --- a/userland/procps/src/main.rs +++ b/userland/procps/src/main.rs @@ -5,7 +5,7 @@ mod bindings { fn main() { let args: Vec = std::env::args().collect(); match std::path::Path::new(&args[0]) - .file_name() + .file_stem() .unwrap() .to_str() .unwrap() diff --git a/userland/spawn/src/lib.rs b/userland/spawn/src/lib.rs index 004ee87..8acd6cf 100644 --- a/userland/spawn/src/lib.rs +++ b/userland/spawn/src/lib.rs @@ -41,13 +41,7 @@ impl Command { pub fn stderr(&mut self, mode: Stdio) -> &mut Self { self.stderr = mode; self } /// Resolve PATH and start the component. pub fn spawn(&self) -> io::Result { - let program = if self.program.contains('/') { self.program.clone() } else { - self.env.get("PATH").map(String::as_str).unwrap_or("/usr/local/bin:/bin").split(':') - .map(|dir| self.cwd.join(dir).join(&self.program)) - .find(|p| p.is_file()).ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, &self.program[..]))? - .to_string_lossy().into_owned() - }; - let child = host::spawn(&host::Request { program, argv: std::iter::once(self.program.clone()).chain(self.args.clone()).collect(), + let child = host::spawn(&host::Request { program: self.program.clone(), argv: std::iter::once(self.program.clone()).chain(self.args.clone()).collect(), env: self.env.clone().into_iter().collect(), cwd: self.cwd.to_string_lossy().into_owned(), group: self.group, stdin: self.stdin, stdout: self.stdout, stderr: self.stderr }).map_err(io::Error::other)?; Ok(Child { stdin: matches!(self.stdin, Stdio::Pipe).then(|| child.stdin()), From cd324678fe86b090c45fa3743b90d9f635b24bef Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 6 Nov 2026 20:04:06 +0000 Subject: [PATCH 02/12] Preserve indexed executable modes in WASI git --- userland/git/src/changes.rs | 18 +++++++++++++++++- userland/git/src/staging.rs | 4 ++-- userland/git/test.nu | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/userland/git/src/changes.rs b/userland/git/src/changes.rs index 5c26ca3..b91fdfe 100644 --- a/userland/git/src/changes.rs +++ b/userland/git/src/changes.rs @@ -238,6 +238,22 @@ pub fn status(repo: &gix::Repository) -> Result { .map_err(|e| error("status", e))?; for item in iter { let item = item.map_err(|e| error("status", e))?; + #[cfg(target_os = "wasi")] + if matches!( + &item, + Item::Modification { + status: gix::status::plumbing::index_as_worktree::EntryStatus::Change( + gix::status::plumbing::index_as_worktree::Change::Modification { + executable_bit_changed: true, + content_change: None, + .. + } + ), + .. + } + ) { + continue; + } let path = item.rela_path().to_str_lossy().into_owned(); let Some(summary) = item.summary() else { continue; @@ -332,7 +348,7 @@ fn worktree_file( } else { entry.mode }; - #[cfg(unix)] + #[cfg(all(unix, not(target_os = "wasi")))] let mode = if mode != 0o120000 && caps.executable_bit { use std::os::unix::fs::PermissionsExt; if meta.permissions().mode() & 0o111 != 0 { diff --git a/userland/git/src/staging.rs b/userland/git/src/staging.rs index d5d873d..a0e59a3 100644 --- a/userland/git/src/staging.rs +++ b/userland/git/src/staging.rs @@ -229,7 +229,7 @@ fn work_entry( Mode::SYMLINK, ) } else if m.is_file() { - #[cfg(unix)] + #[cfg(all(unix, not(target_os = "wasi")))] let mode = { use std::os::unix::fs::PermissionsExt; if m.permissions().mode() & 0o111 != 0 { @@ -238,7 +238,7 @@ fn work_entry( Mode::FILE } }; - #[cfg(not(unix))] + #[cfg(any(not(unix), target_os = "wasi"))] let mode = if previous == Some(Mode::FILE_EXECUTABLE) { Mode::FILE_EXECUTABLE } else { diff --git a/userland/git/test.nu b/userland/git/test.nu index 5b57829..eb0c78b 100644 --- a/userland/git/test.nu +++ b/userland/git/test.nu @@ -268,6 +268,24 @@ def main [component: path] { print $'($args | str join " "): (if $equal {"PASS documented usage"} else {"FAIL documented usage"}) wasi=($result.exit_code)' if not $equal { $failures += 1; print ($result | to json) } } + # WASI checkout and staging retain an existing executable file's indexed mode. + let executable = ($root | path join executable) + mkdir $executable + ^git -C $executable init -q -b main + "#!/bin/sh\necho executable\n" | save ($executable | path join run.sh) + ^chmod +x ($executable | path join run.sh) + ^git -C $executable add run.sh + ^git -C $executable commit --no-gpg-sign -q -m executable + rm ($executable | path join run.sh) + mut executable_ok = true + for args in [[checkout -q HEAD -- run.sh] [status --short] [diff] [add run.sh] [diff --cached] [status --short]] { + let result = (^wasmtime run -S http=y -S cli-exit-with-code=y --dir $'($executable)::/mode' $component -C /mode ...$args | complete) + if $result.exit_code != 0 or $result.stdout != '' { $executable_ok = false; print ($result | to json) } + } + let indexed = (^git -C $executable ls-files --stage run.sh | complete) + $executable_ok = ($executable_ok and $indexed.exit_code == 0 and ($indexed.stdout | str starts-with '100755 ')) + print $'executable checkout stays clean: (if $executable_ok {"PASS"} else {"FAIL"})' + if not $executable_ok { $failures += 1 } # A merge tree that differs from both parents requires a combined diff. 'combined resolution\n' | save --force ($root | path join native/repo/file.txt) let native = ($root | path join native/repo) From abe420f0d48a3d600b9beae71f9f5d9fc7f37bff Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 6 Nov 2026 21:13:40 +0000 Subject: [PATCH 03/12] Make credential requests durable and store proxy authentication --- host/js/README.md | 18 +- host/js/bundle.js | 144 +- host/js/credentials.ts | 49 + host/js/durable-test-bundle.js | 20519 ++++++++++++++++++++++++++++++ host/js/durable-test.ts | 47 + host/js/main.ts | 17 +- host/js/package.json | 2 +- host/src/cred/requests.rs | 1 + host/src/cred/store.rs | 6 + host/src/harness/credentials.rs | 162 + host/src/harness/mod.rs | 51 +- host/tests/durable.rs | 325 + 12 files changed, 21279 insertions(+), 62 deletions(-) create mode 100644 host/js/credentials.ts create mode 100644 host/js/durable-test-bundle.js create mode 100644 host/js/durable-test.ts create mode 100644 host/src/harness/credentials.rs create mode 100644 host/tests/durable.rs diff --git a/host/js/README.md b/host/js/README.md index 263dd74..e09cf5e 100644 --- a/host/js/README.md +++ b/host/js/README.md @@ -35,6 +35,20 @@ For Nix, use a separate npm derivation with `importNpmLock` and the checked-in l Run the bundle script there. Pass its output to the Rust source derivation before Crane builds the host. The Rust build must not execute npm or download JavaScript packages. -The console reads `PI_PROXY_BASE_URL` and `PI_PROXY_API_KEY` from the host environment. -It selects `openai/gpt-6.1-sol` with low reasoning effort. +The console reads the `llm-proxy` credentials item through Rust. +Its public `base_url` field contains the proxy URL. Its secret `api_key` field contains the token. +If the item does not exist, Rust creates it from `PI_PROXY_BASE_URL` and `PI_PROXY_API_KEY` once. +Rust encrypts the token before it commits the item. Later starts ignore these environment variables. +The token enters JavaScript only through an operation. No startup script, transcript, or world file stores it. +The console selects `openai/gpt-6.1-sol` with low reasoning effort. This model rejects disabled reasoning. Tests use the faux provider without credentials. + +Credential requests own background pi-durable tasks in their requesting conversations. +Filed notifications create tasks. Startup reconciliation also creates missing tasks, including requests decided during a host stop. +A conversation document records each request id in the same commit that creates its task. +Program requests create no task. A pending task sleeps durably and checks the decision each second. +The harness also expires requests during these checks. +A decided task admits one plain-language input and completes in one SQLite commit. +The input starts a new turn when the conversation is idle. Neither the input nor the task contains a secret. +The task and its input survive SIGKILL. The input uses a stable request id to prevent duplicate admission. +Hosts with a shared credentials handle can use `run_module_with_credentials`. diff --git a/host/js/bundle.js b/host/js/bundle.js index 490ae91..c168ae9 100644 --- a/host/js/bundle.js +++ b/host/js/bundle.js @@ -33805,9 +33805,9 @@ async function createAgent(tx, conversation) { function agentHooks(agent, taskName) { const handlers = []; for (const extension of agent.extensions) { - for (const hook of extension.hooks ?? []) { - if (hook.task === taskName) - handlers.push({ extension: extension.name, handlers: hook.handlers }); + for (const hook2 of extension.hooks ?? []) { + if (hook2.task === taskName) + handlers.push({ extension: extension.name, handlers: hook2.handlers }); } } return handlers; @@ -33815,7 +33815,7 @@ function agentHooks(agent, taskName) { function sectionExtension(agent, key) { let found; for (const extension of agent.extensions) { - const provides = extension.sections?.some((section) => section.key === key) === true; + const provides = extension.sections?.some((section2) => section2.key === key) === true; const wraps = extension.wraps?.some((wrap) => "section" in wrap && wrap.section === key) === true; if (provides || wraps) found = extension.name; @@ -33840,8 +33840,8 @@ function resolveAgent(state2, snapshot, settings, report2) { composed.set(tool.name, tool); const sections = /* @__PURE__ */ new Map(); for (const extension of extensions) { - for (const section of extension.sections ?? []) - sections.set(section.key, section); + for (const section2 of extension.sections ?? []) + sections.set(section2.key, section2); } for (const extension of extensions) { for (const wrap of extension.wraps ?? []) { @@ -33849,7 +33849,7 @@ function resolveAgent(state2, snapshot, settings, report2) { if ("tool" in wrap) applyWrap(composed, wrap.tool, (tool) => wrap.wrap(tool), (tool) => tool.name, wrapReport); else - applyWrap(sections, wrap.section, (section) => wrap.wrap(section), (section) => section.key, wrapReport); + applyWrap(sections, wrap.section, (section2) => wrap.wrap(section2), (section2) => section2.key, wrapReport); } } const enabled = filterTools([...composed.values()], state2?.tools); @@ -34685,24 +34685,24 @@ function replaySections(messages) { } async function renderSections(sections, input, shown, report2, context) { const desired = /* @__PURE__ */ new Map(); - for (const section of sections) { + for (const section2 of sections) { let text2; try { - text2 = await section.render(input, context); + text2 = await section2.render(input, context); } catch (error) { if (context.abortSignal?.aborted) throw error; - report2(error, section); - const kept = shown.get(section.key); + report2(error, section2); + const kept = shown.get(section2.key); if (kept !== void 0) - desired.set(section.key, kept); + desired.set(section2.key, kept); continue; } if (text2 === void 0) continue; - desired.set(section.key, section.tag === false ? text2 : `<${section.key}> + desired.set(section2.key, section2.tag === false ? text2 : `<${section2.key}> ${text2} -`); +`); } return desired; } @@ -38706,11 +38706,11 @@ var ToolTask = defineTask({ return reject(runtime, task.input, call, tool, invalid(checked.error), context); let args = checked.args; let block; - await runtime.hooks.each("beforeTool", async (hook) => { + await runtime.hooks.each("beforeTool", async (hook2) => { if (block !== void 0) return; try { - const decision = await hook({ ...call, arguments: args }, runtime, context); + const decision = await hook2({ ...call, arguments: args }, runtime, context); if (decision?.block !== void 0) block = decision.block; else if (decision?.arguments !== void 0) @@ -39052,8 +39052,8 @@ async function finalResult(runtime, input, call, tool, result, reported, context details: result.details === void 0 ? reported.details : result.details, diagnostics: [...reported.diagnostics, ...result.diagnostics ?? []] }; - await runtime.hooks.each("afterTool", async (hook) => { - final = await hook(call, final, runtime, context) ?? final; + await runtime.hooks.each("afterTool", async (hook2) => { + final = await hook2(call, final, runtime, context) ?? final; }); if (retained !== void 0 && retained.droppedBytes > 0 && final.output === output) { harness2.push(truncated(retained, reported.limits.retain)); @@ -39085,8 +39085,8 @@ async function finalResult(runtime, input, call, tool, result, reported, context } async function afterHarnessResult(runtime, input, call, tool, result, truncation, context) { let final = result; - await runtime.hooks.each("afterTool", async (hook) => { - final = await hook(call, final, runtime, context) ?? final; + await runtime.hooks.each("afterTool", async (hook2) => { + final = await hook2(call, final, runtime, context) ?? final; }); const harness2 = []; if (truncation !== void 0 && final.output === result.output) @@ -39406,9 +39406,9 @@ var GenerationTask = defineTask({ runtime.report(error, { kind: "host", callback: "env" }); } const input = { conversationId, agent, env, shown: Object.fromEntries(shown), read: runtime }; - const desired = await renderSections(agent.sections, input, shown, (error, section) => runtime.report(error, { + const desired = await renderSections(agent.sections, input, shown, (error, section2) => runtime.report(error, { kind: "extension", - ...optionalExtension(sectionExtension(agent, section.key)) + ...optionalExtension(sectionExtension(agent, section2.key)) }), context); const entries2 = planSystemEntries(view2, desired, agent.tools, runtime.now()); const threshold = compacted === void 0 ? thresholdCompaction(view2, entries2, resolved.contextWindow, compactionPolicy(settings, model3)) : void 0; @@ -39456,8 +39456,8 @@ var GenerationTask = defineTask({ return failNoModel(runtime, ref, context); const view2 = await runtime.context(conversationId, context, { at: cutoff }); let messages = view2.messages; - await runtime.hooks.each("beforeRequest", async (hook) => { - const replaced = await hook({ messages }, runtime, context); + await runtime.hooks.each("beforeRequest", async (hook2) => { + const replaced = await hook2({ messages }, runtime, context); if (replaced !== void 0) messages = replaced.messages; }); @@ -39545,8 +39545,8 @@ var GenerationTask = defineTask({ if (cutOffTooOften(task, runtime)) return endAnsweredCutOff(runtime, task, run2.answer, context); const prepared = []; - await runtime.hooks.each("afterRun", async (hook) => { - const asked = await hook(run2, runtime, context); + await runtime.hooks.each("afterRun", async (hook2) => { + const asked = await hook2(run2, runtime, context); if (asked !== void 0) prepareRunEndTasks(runtime, asked.tasks, prepared); }); @@ -39754,8 +39754,8 @@ async function convertPartial(tx, live, conversationId) { } async function providerPayload(runtime, model3, payload, context) { let current = payload; - await runtime.hooks.each("beforeProviderRequest", async (hook) => { - const replaced = await hook({ model: model3, payload: current }, runtime, context); + await runtime.hooks.each("beforeProviderRequest", async (hook2) => { + const replaced = await hook2({ model: model3, payload: current }, runtime, context); if (replaced !== void 0) current = replaced.payload; }); @@ -39839,7 +39839,7 @@ async function classify2(runtime, request2, message, context) { }, context); return; } - await runtime.hooks.each("afterResponse", (hook) => hook(message, runtime, context)); + await runtime.hooks.each("afterResponse", (hook2) => hook2(message, runtime, context)); const calls = message.content.filter((content) => content.type === "toolCall"); if (message.stopReason === "toolUse" && calls.length > 0) { return startToolRound(runtime, request2, message, calls, context); @@ -39892,10 +39892,10 @@ async function classify2(runtime, request2, message, context) { } async function answer(runtime, message, context) { let continuation; - await runtime.hooks.each("onYield", async (hook) => { + await runtime.hooks.each("onYield", async (hook2) => { if (continuation !== void 0) return; - continuation = (await hook(message, runtime, context))?.continue; + continuation = (await hook2(message, runtime, context))?.continue; }); const afterRun = await asksAfterRun(runtime, context); const conversationId = runtime.conversationId; @@ -40038,7 +40038,7 @@ async function finishToolRound(runtime, assistant, tools, context) { }); const slots = (await runtime.snapshot(LiveDoc, conversationId, context))?.tools ?? []; const results = slots.flatMap((slot) => slot.entry === void 0 ? [] : [slot.entry]); - await runtime.hooks.each("afterTools", (hook) => hook(assistant, results, runtime, context)); + await runtime.hooks.each("afterTools", (hook2) => hook2(assistant, results, runtime, context)); const ordered = slots.map((slot) => slot.taskId === void 0 ? void 0 : controls.get(slot.taskId)); const terminate = slots.length > 0 && ordered.every((control) => control?.terminate === true); const added = ordered.flatMap((control) => control?.addTools ?? []); @@ -40583,9 +40583,9 @@ var CompactionTask = defineTask({ ...instructions === void 0 ? {} : { instructions } }; let decision; - await runtime.hooks.each("beforeCompact", async (hook) => { + await runtime.hooks.each("beforeCompact", async (hook2) => { if (decision === void 0) - decision = await hook(compaction, runtime, context); + decision = await hook2(compaction, runtime, context); }); if (decision !== void 0 && "decline" in decision) return complete(runtime, context); @@ -40919,7 +40919,7 @@ var RegistryState = class { return this.#extensions.flatMap((extension) => (extension.tools ?? []).map((tool) => ({ extension, tool }))); } sections() { - return this.#extensions.flatMap((extension) => (extension.sections ?? []).map((section) => ({ extension, section }))); + return this.#extensions.flatMap((extension) => (extension.sections ?? []).map((section2) => ({ extension, section: section2 }))); } tasks() { return [...this.#tasks.values()]; @@ -44424,10 +44424,67 @@ function environment(cwd = "/", conversation) { return env; } -// main.ts -if (!process.env.PI_PROXY_BASE_URL || !process.env.PI_PROXY_API_KEY) { - throw new Error("PI_PROXY_BASE_URL and PI_PROXY_API_KEY are required"); +// credentials.ts +var Requests = defineDoc({ + kind: "sausage.credential.requests", + version: 1, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({ ids: [] }), + checkpointWhen: () => false +}); +var Wait = defineTask({ + name: "sausage.credential.wait", + version: 1, + initial: () => ({ phase: "wait" }), + phases: { + wait: async (task, runtime, context) => { + const request2 = Deno.core.ops.op_credential_requests().find((r) => r.id === task.input.id); + if (!request2 || request2.state === "pending") { + await runtime.sleepUntil(Date.now() + 1e3, { phase: "wait" }, context); + return; + } + const conversation = await runtime.conversation(runtime.conversationId, context); + await runtime.commit(async (tx) => { + await conversation.submit(tx, { type: "input", content: request2.message, requestId: `credential:${request2.id}` }); + return { status: "terminal", outcome: { status: "completed", result: null } }; + }, context); + } + }, + abort: (_task, runtime, context) => runtime.commit(() => ({ status: "terminal", outcome: { status: "aborted" } }), context) +}); +var CredentialRequests = defineExtension({ name: "sausage.credentials", tasks: [Wait] }); +async function discoverRequests(harness2, context) { + for (const request2 of Deno.core.ops.op_credential_requests()) { + const conversation = await harness2.conversation(Number(request2.conversation), context); + if (!conversation) continue; + await conversation.commit(async (tx) => { + const recorded = await tx.doc(Requests, conversation.id); + if (recorded.ids.includes(request2.id)) return; + await tx.createTask(Wait, { id: request2.id }, { ownership: { kind: "conversation" }, background: true }); + recorded.ids.push(request2.id); + }, context); + } } +async function startRequests(harness2, context) { + await discoverRequests(harness2, context); + let active = true; + const pending = (async () => { + while (active) { + await Deno.core.ops.op_credential_next(); + if (active) await discoverRequests(harness2, context); + } + })(); + return async () => { + active = false; + await pending; + }; +} + +// main.ts +var proxy = Deno.core.ops.op_model_proxy(); +if (!proxy?.base_url || !proxy?.api_key) throw new Error("The llm-proxy credential is required"); var models = createModels(); var provider2 = openaiProvider(); var model2 = { @@ -44435,7 +44492,7 @@ var model2 = { name: "gpt-6.1-sol", provider: "openai", api: "openai-responses", - baseUrl: `${process.env.PI_PROXY_BASE_URL}/v1`, + baseUrl: `${proxy.base_url}/v1`, reasoning: true, input: ["text"], thinkingLevelMap: { off: null, minimal: null }, @@ -44449,21 +44506,22 @@ models.setProvider({ getModels: () => [model2], auth: { apiKey: { name: "Sausage proxy", resolve: async () => ({ auth: { - apiKey: process.env.PI_PROXY_API_KEY, + apiKey: proxy.api_key, baseUrl: model2.baseUrl, headers: { "Shopify-Usage-Tag": JSON.stringify(["pi", "sausage"]) } }, - source: "PI_PROXY_API_KEY" + source: "llm-proxy" }) } } }); var registry = createRegistry(); registry.install(CodingTools); +registry.install(CredentialRequests); var harness = await Harness.open(await openStorage(globalThis.storagePath), { models, registry, env: (target) => environment(target.cwd ?? "/", target.conversationId) }, BACKGROUND_CONTEXT); -var root = await harness.root(BACKGROUND_CONTEXT, { agent: { model: { provider: "openai", modelId: model2.id }, thinkingLevel: "low", cwd: "/", extensions: [CodingTools] } }); +var root = await harness.root(BACKGROUND_CONTEXT, { agent: { model: { provider: "openai", modelId: model2.id }, thinkingLevel: "low", cwd: "/", extensions: [CodingTools, CredentialRequests] } }); var watch = await root.watch(BACKGROUND_CONTEXT); var emitted = /* @__PURE__ */ new Map(); var partial = ""; @@ -44488,6 +44546,7 @@ for (const entry2 of watch.value.entries) { watch.start((event) => { if (event.kind === "value") render(event.value); }); +var stopRequests = await startRequests(harness, BACKGROUND_CONTEXT); harness.resume(); await harness.waitForIdle(BACKGROUND_CONTEXT); while (true) { @@ -44503,5 +44562,6 @@ while (true) { Deno.core.ops.op_output("\n"); if (result.status !== "done") throw new Error(`Run ended: ${JSON.stringify(result)}`); } +await stopRequests(); await watch.stop(); await harness.close(BACKGROUND_CONTEXT); diff --git a/host/js/credentials.ts b/host/js/credentials.ts new file mode 100644 index 0000000..b24b9bd --- /dev/null +++ b/host/js/credentials.ts @@ -0,0 +1,49 @@ +// Durable, background credential waits. Admission and completion share one SQLite commit. +import { defineDoc, defineTask, defineExtension } from '@earendil-works/pi-durable'; +const Requests = defineDoc<{ ids: string[] }>({ + kind: 'sausage.credential.requests', version: 1, scope: 'conversation', + history: 'latest', fork: 'initial', initial: () => ({ ids: [] }), checkpointWhen: () => false, +}); +const Wait = defineTask<{ id: string }, { phase: 'wait' }, null>({ + name: 'sausage.credential.wait', version: 1, initial: () => ({ phase: 'wait' }), + phases: { + wait: async (task, runtime, context) => { + const request = Deno.core.ops.op_credential_requests().find((r: any) => r.id === task.input.id); + if (!request || request.state === 'pending') { + await runtime.sleepUntil(Date.now() + 1000, { phase: 'wait' }, context); + return; + } + const conversation = (await runtime.conversation(runtime.conversationId, context))!; + await runtime.commit(async (tx) => { + await conversation.submit(tx, { type: 'input', content: request.message, requestId: `credential:${request.id}` }); + return { status: 'terminal', outcome: { status: 'completed', result: null } }; + }, context); + }, + }, + abort: (_task, runtime, context) => runtime.commit(() => ({ status: 'terminal', outcome: { status: 'aborted' } }), context), +}); +export const CredentialRequests = defineExtension({ name: 'sausage.credentials', tasks: [Wait] }); +export async function discoverRequests(harness: any, context: any) { + for (const request of Deno.core.ops.op_credential_requests()) { + const conversation = await harness.conversation(Number(request.conversation), context); + if (!conversation) continue; + await conversation.commit(async (tx: any) => { + const recorded = await tx.doc(Requests, conversation.id); + if (recorded.ids.includes(request.id)) return; + await tx.createTask(Wait, { id: request.id }, { ownership: { kind: 'conversation' }, background: true }); + recorded.ids.push(request.id); + }, context); + } +} +export async function startRequests(harness: any, context: any) { + await discoverRequests(harness, context); + // Filed notifications start waits. The deadline reconciles other handles and lost notifications. + let active = true; + const pending = (async () => { + while (active) { + await Deno.core.ops.op_credential_next(); + if (active) await discoverRequests(harness, context); + } + })(); + return async () => { active = false; await pending; }; +} diff --git a/host/js/durable-test-bundle.js b/host/js/durable-test-bundle.js new file mode 100644 index 0000000..6ad5b03 --- /dev/null +++ b/host/js/durable-test-bundle.js @@ -0,0 +1,20519 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + try { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + } catch (e) { + throw mod = 0, e; + } +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// node_modules/partial-json/dist/options.js +var require_options = __commonJS({ + "node_modules/partial-json/dist/options.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Allow = exports.ALL = exports.COLLECTION = exports.ATOM = exports.SPECIAL = exports.INF = exports._INFINITY = exports.INFINITY = exports.NAN = exports.BOOL = exports.NULL = exports.OBJ = exports.ARR = exports.NUM = exports.STR = void 0; + exports.STR = 1; + exports.NUM = 2; + exports.ARR = 4; + exports.OBJ = 8; + exports.NULL = 16; + exports.BOOL = 32; + exports.NAN = 64; + exports.INFINITY = 128; + exports._INFINITY = 256; + exports.INF = exports.INFINITY | exports._INFINITY; + exports.SPECIAL = exports.NULL | exports.BOOL | exports.INF | exports.NAN; + exports.ATOM = exports.STR | exports.NUM | exports.SPECIAL; + exports.COLLECTION = exports.ARR | exports.OBJ; + exports.ALL = exports.ATOM | exports.COLLECTION; + exports.Allow = { STR: exports.STR, NUM: exports.NUM, ARR: exports.ARR, OBJ: exports.OBJ, NULL: exports.NULL, BOOL: exports.BOOL, NAN: exports.NAN, INFINITY: exports.INFINITY, _INFINITY: exports._INFINITY, INF: exports.INF, SPECIAL: exports.SPECIAL, ATOM: exports.ATOM, COLLECTION: exports.COLLECTION, ALL: exports.ALL }; + exports.default = exports.Allow; + } +}); + +// node_modules/partial-json/dist/index.js +var require_dist = __commonJS({ + "node_modules/partial-json/dist/index.js"(exports) { + "use strict"; + var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) { + if (k2 === void 0) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { + return m[k]; + } }; + } + Object.defineProperty(o, k2, desc); + }) : (function(o, m, k, k2) { + if (k2 === void 0) k2 = k; + o[k2] = m[k]; + })); + var __exportStar = exports && exports.__exportStar || function(m, exports2) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p); + }; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Allow = exports.MalformedJSON = exports.PartialJSON = exports.parseJSON = exports.parse = void 0; + var options_1 = require_options(); + Object.defineProperty(exports, "Allow", { enumerable: true, get: function() { + return options_1.Allow; + } }); + __exportStar(require_options(), exports); + var PartialJSON = class extends Error { + }; + exports.PartialJSON = PartialJSON; + var MalformedJSON = class extends Error { + }; + exports.MalformedJSON = MalformedJSON; + function parseJSON(jsonString, allowPartial = options_1.Allow.ALL) { + if (typeof jsonString !== "string") { + throw new TypeError(`expecting str, got ${typeof jsonString}`); + } + if (!jsonString.trim()) { + throw new Error(`${jsonString} is empty`); + } + return _parseJSON(jsonString.trim(), allowPartial); + } + exports.parseJSON = parseJSON; + var _parseJSON = (jsonString, allow) => { + const length = jsonString.length; + let index = 0; + const markPartialJSON = (msg) => { + throw new PartialJSON(`${msg} at position ${index}`); + }; + const throwMalformedError = (msg) => { + throw new MalformedJSON(`${msg} at position ${index}`); + }; + const parseAny = () => { + skipBlank(); + if (index >= length) + markPartialJSON("Unexpected end of input"); + if (jsonString[index] === '"') + return parseStr(); + if (jsonString[index] === "{") + return parseObj(); + if (jsonString[index] === "[") + return parseArr(); + if (jsonString.substring(index, index + 4) === "null" || options_1.Allow.NULL & allow && length - index < 4 && "null".startsWith(jsonString.substring(index))) { + index += 4; + return null; + } + if (jsonString.substring(index, index + 4) === "true" || options_1.Allow.BOOL & allow && length - index < 4 && "true".startsWith(jsonString.substring(index))) { + index += 4; + return true; + } + if (jsonString.substring(index, index + 5) === "false" || options_1.Allow.BOOL & allow && length - index < 5 && "false".startsWith(jsonString.substring(index))) { + index += 5; + return false; + } + if (jsonString.substring(index, index + 8) === "Infinity" || options_1.Allow.INFINITY & allow && length - index < 8 && "Infinity".startsWith(jsonString.substring(index))) { + index += 8; + return Infinity; + } + if (jsonString.substring(index, index + 9) === "-Infinity" || options_1.Allow._INFINITY & allow && 1 < length - index && length - index < 9 && "-Infinity".startsWith(jsonString.substring(index))) { + index += 9; + return -Infinity; + } + if (jsonString.substring(index, index + 3) === "NaN" || options_1.Allow.NAN & allow && length - index < 3 && "NaN".startsWith(jsonString.substring(index))) { + index += 3; + return NaN; + } + return parseNum(); + }; + const parseStr = () => { + const start = index; + let escape = false; + index++; + while (index < length && (jsonString[index] !== '"' || escape && jsonString[index - 1] === "\\")) { + escape = jsonString[index] === "\\" ? !escape : false; + index++; + } + if (jsonString.charAt(index) == '"') { + try { + return JSON.parse(jsonString.substring(start, ++index - Number(escape))); + } catch (e) { + throwMalformedError(String(e)); + } + } else if (options_1.Allow.STR & allow) { + try { + return JSON.parse(jsonString.substring(start, index - Number(escape)) + '"'); + } catch (e) { + return JSON.parse(jsonString.substring(start, jsonString.lastIndexOf("\\")) + '"'); + } + } + markPartialJSON("Unterminated string literal"); + }; + const parseObj = () => { + index++; + skipBlank(); + const obj = {}; + try { + while (jsonString[index] !== "}") { + skipBlank(); + if (index >= length && options_1.Allow.OBJ & allow) + return obj; + const key = parseStr(); + skipBlank(); + index++; + try { + const value2 = parseAny(); + obj[key] = value2; + } catch (e) { + if (options_1.Allow.OBJ & allow) + return obj; + else + throw e; + } + skipBlank(); + if (jsonString[index] === ",") + index++; + } + } catch (e) { + if (options_1.Allow.OBJ & allow) + return obj; + else + markPartialJSON("Expected '}' at end of object"); + } + index++; + return obj; + }; + const parseArr = () => { + index++; + const arr = []; + try { + while (jsonString[index] !== "]") { + arr.push(parseAny()); + skipBlank(); + if (jsonString[index] === ",") { + index++; + } + } + } catch (e) { + if (options_1.Allow.ARR & allow) { + return arr; + } + markPartialJSON("Expected ']' at end of array"); + } + index++; + return arr; + }; + const parseNum = () => { + if (index === 0) { + if (jsonString === "-") + throwMalformedError("Not sure what '-' is"); + try { + return JSON.parse(jsonString); + } catch (e) { + if (options_1.Allow.NUM & allow) + try { + return JSON.parse(jsonString.substring(0, jsonString.lastIndexOf("e"))); + } catch (e2) { + } + throwMalformedError(String(e)); + } + } + const start = index; + if (jsonString[index] === "-") + index++; + while (jsonString[index] && ",]}".indexOf(jsonString[index]) === -1) + index++; + if (index == length && !(options_1.Allow.NUM & allow)) + markPartialJSON("Unterminated number literal"); + try { + return JSON.parse(jsonString.substring(start, index)); + } catch (e) { + if (jsonString.substring(start, index) === "-") + markPartialJSON("Not sure what '-' is"); + try { + return JSON.parse(jsonString.substring(start, jsonString.lastIndexOf("e"))); + } catch (e2) { + throwMalformedError(String(e2)); + } + } + }; + const skipBlank = () => { + while (index < length && " \n\r ".includes(jsonString[index])) { + index++; + } + }; + return parseAny(); + }; + var parse = parseJSON; + exports.parse = parse; + } +}); + +// node_modules/@earendil-works/pi-telemetry/dist/metrics.js +function createTypedMetrics(metrics, schemas) { + const definitions = /* @__PURE__ */ new Map(); + for (const schema of schemas) { + for (const [name, definition] of Object.entries(schema.metrics ?? {})) + definitions.set(name, definition); + } + return { + counter: (name) => metrics.counter(name, definitions.get(name)), + upDownCounter: (name) => metrics.upDownCounter(name, definitions.get(name)), + histogram: (name) => metrics.histogram(name, definitions.get(name)) + }; +} + +// node_modules/@earendil-works/pi-telemetry/dist/noop.js +async function startNoopSpan(_options, callback) { + return callback(noopTelemetrySpan); +} +var noopCounter = Object.freeze({ add: () => { +} }); +var noopUpDownCounter = Object.freeze({ add: () => { +} }); +var noopHistogram = Object.freeze({ record: () => { +} }); +var NOOP_TELEMETRY_METRICS = Object.freeze({ + counter: () => noopCounter, + upDownCounter: () => noopUpDownCounter, + histogram: () => noopHistogram +}); +var NOOP_TELEMETRY_PROPAGATION = Object.freeze({ + inject: () => void 0, + extract: () => NOOP_TELEMETRY_CONTEXT +}); +var noopTelemetrySpan = { + metrics: NOOP_TELEMETRY_METRICS, + propagation: NOOP_TELEMETRY_PROPAGATION, + startSpan: startNoopSpan, + addLink: () => { + }, + addEvent: () => { + }, + setAttributes: () => { + }, + setStatus: () => { + } +}; +Object.freeze(noopTelemetrySpan); +var NOOP_TELEMETRY_CONTEXT = noopTelemetrySpan; + +// node_modules/@earendil-works/pi-telemetry/dist/index.js +function defineTelemetrySchema(schema) { + return schema; +} +function bindTypedSpanStarter(telemetryContext) { + const startSpan = (name, attributes, callback) => telemetryContext.startSpan({ name, attributes }, (span) => callback(span, bindTypedSpanStarter(span))); + return startSpan; +} +function createTypedSpanStarter(telemetryContext, _schemas) { + return bindTypedSpanStarter(telemetryContext); +} + +// node_modules/@earendil-works/chord/dist/context/index.js +var ABORT_SIGNAL_CONTEXT_KEY = Object.freeze({ + token: /* @__PURE__ */ Symbol("chord.abortSignal") +}); +var TELEMETRY_CONTEXT_KEY = Object.freeze({ + token: /* @__PURE__ */ Symbol("chord.telemetry") +}); +var BaseContext = class { + get abortSignal() { + return this.value(ABORT_SIGNAL_CONTEXT_KEY); + } + get telemetry() { + return this.value(TELEMETRY_CONTEXT_KEY) ?? NOOP_TELEMETRY_CONTEXT; + } +}; +var EmptyContext = class extends BaseContext { + #name; + constructor(name) { + super(); + this.#name = name; + } + value(_key) { + return void 0; + } + toString() { + return this.#name; + } +}; +var ContextValue = class extends BaseContext { + #parent; + #key; + #value; + constructor(parent, key, value2) { + super(); + this.#parent = parent; + this.#key = key; + this.#value = value2; + } + value(key) { + if (key.token === this.#key.token) + return this.#value; + return this.#parent.value(key); + } + toString() { + return `${this.#parent}.WithValue(${this.#key.token.description ?? "anonymous"})`; + } +}; +var BACKGROUND_CONTEXT = new EmptyContext("[Context BACKGROUND_CONTEXT]"); +var TODO_CONTEXT = new EmptyContext("[Context TODO_CONTEXT]"); +function withContextValue(key, value2, parent) { + return new ContextValue(parent, key, value2); +} +function withTelemetry(telemetry, context) { + return withContextValue(TELEMETRY_CONTEXT_KEY, telemetry, context); +} +function withAbortSignal(signal, context) { + const parentSignal = context.abortSignal; + const combined = parentSignal === void 0 ? signal : AbortSignal.any([parentSignal, signal]); + return withContextValue(ABORT_SIGNAL_CONTEXT_KEY, combined, context); +} +function withoutAbortSignal(context) { + return withContextValue(ABORT_SIGNAL_CONTEXT_KEY, void 0, context); +} +function awaitWithContext(promise, context) { + const signal = context.abortSignal; + if (signal === void 0) + return promise; + if (signal.aborted) + return Promise.reject(abortError(signal)); + return new Promise((resolve2, reject2) => { + const onAbort = () => reject2(abortError(signal)); + signal.addEventListener("abort", onAbort, { once: true }); + void promise.then((value2) => { + signal.removeEventListener("abort", onAbort); + resolve2(value2); + }, (error) => { + signal.removeEventListener("abort", onAbort); + reject2(error); + }); + }); +} +function abortError(signal) { + const reason = signal.reason; + return reason instanceof Error ? reason : new DOMException("The operation was aborted", "AbortError"); +} + +// node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js +var FifoQueue = class { + incoming = []; + outgoing = []; + get length() { + return this.incoming.length + this.outgoing.length; + } + enqueue(value2) { + this.incoming.push(value2); + } + dequeue() { + if (this.outgoing.length === 0) { + while (this.incoming.length > 0) { + this.outgoing.push(this.incoming.pop()); + } + } + return this.outgoing.pop(); + } +}; +var EventStream = class { + queue = new FifoQueue(); + waiting = new FifoQueue(); + done = false; + finalResultPromise; + resolveFinalResult; + isComplete; + extractResult; + constructor(isComplete, extractResult) { + this.isComplete = isComplete; + this.extractResult = extractResult; + this.finalResultPromise = new Promise((resolve2) => { + this.resolveFinalResult = resolve2; + }); + } + push(event) { + if (this.done) + return; + if (this.isComplete(event)) { + this.done = true; + this.resolveFinalResult(this.extractResult(event)); + } + const waiter = this.waiting.dequeue(); + if (waiter) { + waiter({ value: event, done: false }); + } else { + this.queue.enqueue(event); + } + } + end(result) { + this.done = true; + if (result !== void 0) { + this.resolveFinalResult(result); + } + while (this.waiting.length > 0) { + const waiter = this.waiting.dequeue(); + waiter({ value: void 0, done: true }); + } + } + async *[Symbol.asyncIterator]() { + while (true) { + if (this.queue.length > 0) { + yield this.queue.dequeue(); + } else if (this.done) { + return; + } else { + const result = await new Promise((resolve2) => this.waiting.enqueue(resolve2)); + if (result.done) + return; + yield result.value; + } + } + } + result() { + return this.finalResultPromise; + } +}; +var AssistantMessageEventStream = class extends EventStream { + #startedAt = Date.now(); + #startedAtMonotonic = performance.now(); + constructor() { + super((event) => event.type === "done" || event.type === "error", (event) => { + if (event.type === "done") { + return event.message; + } else if (event.type === "error") { + return event.error; + } + throw new Error("Unexpected event type for final result"); + }); + } + push(event) { + if (event.type === "done") + this.#time(event.message); + else if (event.type === "error") + this.#time(event.error); + super.push(event); + } + end(result) { + if (result !== void 0) + this.#time(result); + super.end(result); + } + #time(message) { + if (this.done || message.durationMs !== void 0 || message.timestamp < this.#startedAt) + return; + message.durationMs = Math.max(0, Math.round(performance.now() - this.#startedAtMonotonic)); + } +}; +function createAssistantMessageEventStream() { + return new AssistantMessageEventStream(); +} + +// node_modules/@earendil-works/pi-ai/dist/api/lazy.js +function createSetupErrorMessage(model2, error, timestamp) { + return { + role: "assistant", + content: [], + api: model2.api, + provider: model2.provider, + model: model2.id, + usage: { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + totalTokens: 0, + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } + }, + stopReason: "error", + errorMessage: error instanceof Error ? error.message : String(error), + timestamp + }; +} +function hasResult(source) { + return typeof source.result === "function"; +} +async function forwardStream(target, source, observer, observeResult) { + let result; + for await (const event of source) { + target.push(event); + observer?.onEvent?.(event); + if (event.type === "done") + result = event.message; + else if (event.type === "error") + result = event.error; + } + if (hasResult(source)) + result = await source.result(); + target.end(result); + observeResult(result); +} +function lazyStream(model2, setup, observer) { + const startedAt = Date.now(); + const outer = new AssistantMessageEventStream(); + let observedResult = false; + const observeResult = (result) => { + if (observedResult) + return; + observedResult = true; + observer?.onResult?.(result); + }; + setup().then((inner) => forwardStream(outer, inner, observer, observeResult)).catch((error) => { + const message = createSetupErrorMessage(model2, error, startedAt); + const event = { type: "error", reason: "error", error: message }; + outer.push(event); + observer?.onEvent?.(event); + outer.end(message); + observeResult(message); + }); + return outer; +} + +// node_modules/@earendil-works/pi-ai/dist/auth/context.js +var __rewriteRelativeImportExtension = function(path, preserveJsx) { + if (typeof path === "string" && /^\.\.?\//.test(path)) { + return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) { + return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js"; + }); + } + return path; +}; +var importNodeModule = (specifier) => import(__rewriteRelativeImportExtension(specifier)); +function getProcessEnv() { + const proc = globalThis.process; + return proc?.env; +} +function defaultProviderAuthContext() { + return { + async env(name) { + const value2 = getProcessEnv()?.[name]; + return typeof value2 === "string" && value2.trim().length > 0 ? value2 : void 0; + }, + async fileExists(path) { + try { + const fs = await importNodeModule("node:fs/promises"); + let resolved = path; + if (resolved.startsWith("~")) { + const os = await importNodeModule("node:os"); + resolved = os.homedir() + resolved.slice(1); + } + await fs.access(resolved); + return true; + } catch { + return false; + } + } + }; +} + +// node_modules/@earendil-works/pi-ai/dist/utils/abort.js +function abortReason(signal) { + if (signal.reason !== void 0) + return signal.reason; + const error = new Error("The operation was aborted"); + error.name = "AbortError"; + return error; +} +function operationSignal(signal) { + return signal ?? new AbortController().signal; +} +function raceWithAbortSignal(operation, signal) { + if (signal.aborted) { + void operation.catch(() => { + }); + return Promise.reject(abortReason(signal)); + } + return new Promise((resolve2, reject2) => { + let settled = false; + const cleanup = () => signal.removeEventListener("abort", onAbort); + const onAbort = () => { + if (settled) + return; + settled = true; + cleanup(); + reject2(abortReason(signal)); + }; + signal.addEventListener("abort", onAbort, { once: true }); + void operation.then((value2) => { + if (settled) + return; + settled = true; + cleanup(); + resolve2(value2); + }, (error) => { + if (settled) + return; + settled = true; + cleanup(); + reject2(error); + }); + if (signal.aborted) + onAbort(); + }); +} + +// node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js +var InMemoryCredentialStore = class { + credentials = /* @__PURE__ */ new Map(); + chains = /* @__PURE__ */ new Map(); + /** Serialize tasks per provider id without releasing the chain before active work settles. */ + enqueue(providerId, task, options) { + const signal = operationSignal(options?.signal); + const previous = this.chains.get(providerId) ?? Promise.resolve(); + const queued = (async () => { + await previous.catch(() => { + }); + signal.throwIfAborted(); + return task(); + })(); + const tail = queued.catch(() => { + }); + this.chains.set(providerId, tail); + void tail.then(() => { + if (this.chains.get(providerId) === tail) + this.chains.delete(providerId); + }); + return raceWithAbortSignal(queued, signal); + } + async read(providerId, options) { + options?.signal?.throwIfAborted(); + return this.credentials.get(providerId); + } + async list(options) { + options?.signal?.throwIfAborted(); + return [...this.credentials].map(([providerId, credential]) => ({ providerId, type: credential.type })); + } + modify(providerId, fn, options) { + return this.enqueue(providerId, async () => { + const current = this.credentials.get(providerId); + const next = await fn(current); + options?.signal?.throwIfAborted(); + if (next !== void 0) + this.credentials.set(providerId, next); + return next ?? current; + }, options); + } + delete(providerId, options) { + return this.enqueue(providerId, async () => { + this.credentials.delete(providerId); + }, options); + } +}; + +// node_modules/@earendil-works/pi-ai/dist/utils/diagnostics.js +function formatThrownValue(value2) { + if (value2 instanceof Error) + return value2.message || value2.name; + if (typeof value2 === "string") + return value2; + return String(value2); +} + +// node_modules/@earendil-works/pi-ai/dist/utils/models-error.js +var ModelsError = class extends Error { + code; + constructor(code, message, options) { + super(withCauseDetail(message, options?.cause), options); + this.name = "ModelsError"; + this.code = code; + } +}; +function withCauseDetail(message, cause) { + if (cause === void 0 || cause === null) + return message; + const detail = formatThrownValue(cause).trim(); + if (!detail || message.includes(detail)) + return message; + return `${message}: ${detail}`; +} + +// node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +function resolveProviderAuth(provider2, credentials, authContext, overrides) { + const signal = operationSignal(overrides?.signal); + return raceWithAbortSignal(resolveProviderAuthWithSignal(provider2, credentials, authContext, overrides, signal), signal); +} +async function resolveProviderAuthWithSignal(provider2, credentials, authContext, overrides, signal) { + signal.throwIfAborted(); + const requestAuthContext = overrides?.env ? overlayEnvAuthContext(authContext, overrides.env) : authContext; + if (overrides?.apiKey !== void 0 && provider2.auth.apiKey) { + return resolveApiKey(requestAuthContext, provider2.auth.apiKey, provider2.id, { + type: "api_key", + key: overrides.apiKey, + env: overrides.env + }, signal); + } + const stored = await readCredential(credentials, provider2.id, signal); + if (stored) { + if (stored.type === "oauth" && provider2.auth.oauth) { + return resolveStoredOAuth(credentials, provider2.id, provider2.auth.oauth, stored, signal, overrides?.minOAuthValidityMs); + } + if (stored.type === "api_key" && provider2.auth.apiKey) { + const credential = overrides?.env ? { ...stored, env: { ...stored.env, ...overrides.env } } : stored; + return resolveApiKey(requestAuthContext, provider2.auth.apiKey, provider2.id, credential, signal); + } + return void 0; + } + return provider2.auth.apiKey ? resolveApiKey(requestAuthContext, provider2.auth.apiKey, provider2.id, void 0, signal) : void 0; +} +function overlayEnvAuthContext(base, env) { + return { + env: async (name) => env[name] || await base.env(name), + fileExists: (path) => base.fileExists(path) + }; +} +var DEFAULT_OAUTH_MINIMUM_VALIDITY_MS = 5 * 60 * 1e3; +var DEFAULT_OAUTH_REFRESH_TIMEOUT_MS = 15e3; +async function refreshStoredOAuthCredential(credentials, providerId, oauth, needsRefresh, signal) { + let post; + const lockWait = new AbortController(); + const cancelLockWait = () => lockWait.abort(signal.reason); + signal.addEventListener("abort", cancelLockWait, { once: true }); + if (signal.aborted) + cancelLockWait(); + try { + post = await credentials.modify(providerId, async (current) => { + signal.removeEventListener("abort", cancelLockWait); + signal.throwIfAborted(); + if (current?.type !== "oauth") + return void 0; + if (!needsRefresh(current)) + return void 0; + try { + return await oauth.refresh(current, AbortSignal.timeout(DEFAULT_OAUTH_REFRESH_TIMEOUT_MS)); + } catch (error) { + throw new ModelsError("oauth", `OAuth refresh failed for ${providerId}`, { cause: error }); + } + }, { signal: lockWait.signal }); + } catch (error) { + if (error instanceof ModelsError) + throw error; + signal.throwIfAborted(); + throw new ModelsError("auth", `Credential store modify failed for ${providerId}`, { cause: error }); + } finally { + signal.removeEventListener("abort", cancelLockWait); + } + return post?.type === "oauth" ? post : void 0; +} +async function resolveStoredOAuth(credentials, providerId, oauth, stored, signal, minOAuthValidityMs) { + const minimumValidityMs = Math.max(DEFAULT_OAUTH_MINIMUM_VALIDITY_MS, minOAuthValidityMs ?? 0); + const expiresSoon = (credential2) => Date.now() + minimumValidityMs >= credential2.expires; + let credential = stored; + if (expiresSoon(credential)) { + const post = await refreshStoredOAuthCredential(credentials, providerId, oauth, expiresSoon, signal); + if (!post) + return void 0; + credential = post; + if (minOAuthValidityMs !== void 0 && expiresSoon(credential)) { + throw new ModelsError("oauth", `OAuth refresh returned a token that expires too soon for ${providerId}`); + } + } + try { + return { auth: await oauth.toAuth(credential), source: "OAuth" }; + } catch (error) { + throw new ModelsError("oauth", `OAuth auth derivation failed for ${providerId}`, { cause: error }); + } +} +async function resolveApiKey(authContext, apiKey, providerId, credential, signal) { + try { + return await apiKey.resolve({ ctx: authContext, credential, signal }); + } catch (error) { + throw new ModelsError("auth", `API key auth failed for provider ${providerId}`, { cause: error }); + } +} +async function readCredential(credentials, providerId, signal) { + try { + return await credentials.read(providerId, { signal }); + } catch (error) { + throw new ModelsError("auth", `Credential store read failed for ${providerId}`, { cause: error }); + } +} + +// node_modules/@earendil-works/pi-ai/dist/models-store.js +var InMemoryModelsStore = class { + entries = /* @__PURE__ */ new Map(); + async read(providerId, options) { + options?.signal?.throwIfAborted(); + const entry2 = this.entries.get(providerId); + return entry2 ? structuredClone(entry2) : void 0; + } + async write(providerId, entry2, options) { + options?.signal?.throwIfAborted(); + this.entries.set(providerId, structuredClone(entry2)); + } + async delete(providerId, options) { + options?.signal?.throwIfAborted(); + this.entries.delete(providerId); + } +}; + +// node_modules/@earendil-works/pi-ai/dist/utils/text.js +function contentText(content, separator = "\n") { + if (typeof content === "string") + return content; + return content.filter((block) => block.type === "text").map((block) => block.text).join(separator); +} +function getSystemMessageText(message) { + const parts = [contentText(message.content)]; + for (const text of Object.values(message.sections ?? {})) { + if (text !== null) + parts.push(text); + } + return parts.filter((part) => part.length > 0).join("\n\n"); +} +function ownedSlice(text, start, end = text.length) { + return `${text.slice(start, end)} `.slice(0, -1); +} + +// node_modules/@earendil-works/pi-ai/dist/telemetry.js +var provider = { type: "string", description: "Provider identifier.", required: true }; +var model = { type: "string", description: "Requested model identifier.", required: true }; +var stop = { + type: "string", + description: "Normalized stop reason.", + values: ["pending", "stop", "length", "toolUse", "error", "aborted", "deferred"] +}; +var request = { + description: "One logical model request, including authentication and provider setup.", + parents: { kind: "any" }, + startAttributes: { + provider, + api: { type: "string", description: "API identifier.", required: true }, + model, + reasoning: { type: "string", description: "Scalar requested reasoning level.", required: false } + }, + endAttributes: { + stop, + "usage.input": { type: "number", description: "Uncached input tokens." }, + "usage.output": { type: "number", description: "Output tokens." }, + "usage.cache_read": { type: "number", description: "Cache-read tokens." }, + "usage.cache_write": { type: "number", description: "Cache-write tokens." }, + "cost.total": { type: "number", description: "Total request cost in USD." }, + "response.id": { type: "string", description: "Provider response identifier.", cardinality: "high" } + }, + events: { + "pi.ai.first_chunk": { description: "First normalized stream event delivered.", attributes: {} }, + "pi.ai.block": { + description: "A completed content block; content is never recorded.", + attributes: { + type: { + type: "string", + description: "Block kind.", + values: ["text", "thinking", "tool_call"], + required: true + }, + index: { type: "number", description: "Content block index.", required: true }, + chars: { type: "number", description: "UTF-16 character count.", required: true }, + tool: { type: "string", description: "Tool name, for tool-call blocks only.", required: false } + } + } + }, + status: { + default: "ok", + errorWhen: "Stop reason is error: provider_error with at most 500 error-message characters. Aborted stays ok." + } +}; +var AI_TELEMETRY_SCHEMA = defineTelemetrySchema({ + version: 1, + spans: { + "pi.ai.request": request, + "pi.ai.poll": { ...request, description: "One deferred-response poll, not the deferred request's lifetime." } + }, + metrics: { + "pi.ai.request.duration": { + kind: "histogram", + description: "Logical request or poll duration.", + unit: "ms", + attributes: { provider, model, stop: { ...stop, required: true } } + }, + "pi.ai.first_chunk.duration": { + kind: "histogram", + description: "Time to the first normalized stream event.", + unit: "ms", + attributes: { provider, model } + }, + "pi.ai.tokens": { + kind: "counter", + description: "Reported model token usage; pending and deferred polls are excluded.", + unit: "token", + attributes: { + provider, + model, + kind: { + type: "string", + description: "Token usage category.", + values: ["input", "output", "cache_read", "cache_write"], + required: true + } + } + }, + "pi.ai.cost": { + kind: "counter", + description: "Reported model cost; pending and deferred polls are excluded.", + unit: "USD", + attributes: { provider, model } + } + } +}); +function createInstruments(adapter) { + const metrics = createTypedMetrics(adapter, [AI_TELEMETRY_SCHEMA]); + return { + requestDuration: metrics.histogram("pi.ai.request.duration"), + firstChunkDuration: metrics.histogram("pi.ai.first_chunk.duration"), + tokens: metrics.counter("pi.ai.tokens"), + cost: metrics.counter("pi.ai.cost") + }; +} +var instrumentCache = /* @__PURE__ */ new WeakMap(); +function observeModelRequest(requestedModel, options, poll) { + const started = performance.now(); + const attributes = { provider: requestedModel.provider, model: requestedModel.id }; + const adapter = options?.telemetry?.metrics ?? NOOP_TELEMETRY_METRICS; + let instruments = instrumentCache.get(adapter); + if (!instruments) { + instruments = createInstruments(adapter); + instrumentCache.set(adapter, instruments); + } + const { requestDuration, firstChunkDuration, tokens, cost } = instruments; + let span; + let finish; + let first = true; + const toolChars = /* @__PURE__ */ new Map(); + const finished = new Promise((resolve2) => { + finish = resolve2; + }); + const run2 = (activeSpan) => { + span = activeSpan; + return finished; + }; + const startAttributes = { + ...attributes, + api: requestedModel.api, + ...typeof options?.reasoning === "string" ? { reasoning: options.reasoning } : {} + }; + const start = createTypedSpanStarter(options?.telemetry ?? NOOP_TELEMETRY_CONTEXT, [AI_TELEMETRY_SCHEMA]); + if (poll) + void start("pi.ai.poll", startAttributes, run2); + else + void start("pi.ai.request", startAttributes, run2); + return { + onEvent(event) { + if (first) { + first = false; + span.addEvent("pi.ai.first_chunk"); + firstChunkDuration.record(performance.now() - started, attributes, span); + } + if (event.type === "toolcall_delta") { + toolChars.set(event.contentIndex, (toolChars.get(event.contentIndex) ?? 0) + event.delta.length); + } else if (event.type === "text_end" || event.type === "thinking_end") { + span.addEvent("pi.ai.block", { + type: event.type === "text_end" ? "text" : "thinking", + index: event.contentIndex, + chars: event.content.length + }); + } else if (event.type === "toolcall_end") { + const chars = toolChars.get(event.contentIndex) ?? 0; + toolChars.delete(event.contentIndex); + span.addEvent("pi.ai.block", { + type: "tool_call", + index: event.contentIndex, + chars, + tool: event.toolCall.name + }); + } + }, + onResult(message) { + if (message) { + span.setAttributes({ + stop: message.stopReason, + "usage.input": message.usage.input, + "usage.output": message.usage.output, + "usage.cache_read": message.usage.cacheRead, + "usage.cache_write": message.usage.cacheWrite, + "cost.total": message.usage.cost.total, + "response.id": message.responseId + }); + if (message.stopReason === "error") { + span.setStatus({ + status: "error", + error: { name: "provider_error", message: ownedSlice(message.errorMessage ?? "", 0, 500) } + }); + } + requestDuration.record(performance.now() - started, { ...attributes, stop: message.stopReason }, span); + if (!poll || message.stopReason !== "pending" && message.stopReason !== "deferred") { + tokens.add(message.usage.input, { ...attributes, kind: "input" }); + tokens.add(message.usage.output, { ...attributes, kind: "output" }); + tokens.add(message.usage.cacheRead, { ...attributes, kind: "cache_read" }); + tokens.add(message.usage.cacheWrite, { ...attributes, kind: "cache_write" }); + cost.add(message.usage.cost.total, attributes); + } + } + finish(); + } + }; +} + +// node_modules/@earendil-works/pi-ai/dist/utils/identity.js +var PI_ATTRIBUTION = { name: "pi", url: "https://pi.dev", categories: ["cli-agent"] }; +var OPENCODE_HOST = "opencode.ai"; +function mergeClientIdentity(...sources) { + let merged; + for (const source of sources) { + if (!source) + continue; + merged = { ...merged }; + if (source.userAgent !== void 0) + merged.userAgent = source.userAgent; + if (source.attribution !== void 0) + merged.attribution = source.attribution; + if (source.version !== void 0) + merged.version = source.version; + } + return merged; +} +function matchesHost(baseUrl, expectedHost) { + try { + return new URL(baseUrl).hostname === expectedHost; + } catch { + return false; + } +} +function isOpenCode(target) { + return target.provider === "opencode" || target.provider === "opencode-go" || matchesHost(target.baseUrl, OPENCODE_HOST); +} +function getOpenCodeSessionHeaders(target, sessionId) { + return sessionId && isOpenCode(target) ? { "x-opencode-session": sessionId } : void 0; +} +function isMutableModels(models2) { + return "setProvider" in models2 && "deleteProvider" in models2 && "clearProviders" in models2; +} +function withClientIdentity(models2, identity) { + const withIdentity = (options) => ({ ...options, identity: mergeClientIdentity(identity, options?.identity) }); + const wrapped = { + getProviders: () => models2.getProviders(), + getProvider: (id) => models2.getProvider(id), + getModels: (provider2) => models2.getModels(provider2), + getModel: (provider2, id) => models2.getModel(provider2, id), + getModelsOfType: (type, provider2) => models2.getModelsOfType(type, provider2), + getModelOfType: (type, provider2, id) => models2.getModelOfType(type, provider2, id), + getAllModels: (provider2) => models2.getAllModels(provider2), + refresh: (options) => models2.refresh(options), + checkAuth: (providerId, options) => models2.checkAuth(providerId, options), + getAvailable: (providerId, options) => models2.getAvailable(providerId, options), + getAvailableOfType: (type, providerId, options) => models2.getAvailableOfType(type, providerId, options), + getAllAvailable: (providerId, options) => models2.getAllAvailable(providerId, options), + getAuth: models2.getAuth.bind(models2), + login: (providerId, type, interaction, options) => models2.login(providerId, type, interaction, options), + logout: (providerId, options) => models2.logout(providerId, options), + stream: (model2, context, options) => models2.stream(model2, context, withIdentity(options)), + complete: (model2, context, options) => models2.complete(model2, context, withIdentity(options)), + streamSimple: (model2, context, options) => models2.streamSimple(model2, context, withIdentity(options)), + completeSimple: (model2, context, options) => models2.completeSimple(model2, context, withIdentity(options)), + streamDeferred: (model2, handle, options) => models2.streamDeferred(model2, handle, withIdentity(options)), + fetchDeferred: (model2, handle, options) => models2.fetchDeferred(model2, handle, withIdentity(options)), + cancelDeferred: (model2, handle, options) => models2.cancelDeferred(model2, handle, withIdentity(options)), + generateImages: (model2, context, options) => models2.generateImages(model2, context, withIdentity(options)), + classify: (model2, context, options) => models2.classify(model2, context, withIdentity(options)) + }; + if (!isMutableModels(models2)) + return wrapped; + const mutable = { + ...wrapped, + setProvider: (provider2) => models2.setProvider(provider2), + deleteProvider: (id) => models2.deleteProvider(id), + clearProviders: () => models2.clearProviders() + }; + return mutable; +} + +// node_modules/@earendil-works/pi-ai/dist/utils/model-operations.js +function getModelType(model2) { + return model2.type ?? "chat"; +} +function isModelType(model2, type) { + return getModelType(model2) === type; +} +function assertChatModel(model2) { + if (!isModelType(model2, "chat")) { + throw new ModelsError("provider", `Model ${model2.provider}/${model2.id} is not a chat model`); + } +} +function assertImageModel(model2) { + if (!isModelType(model2, "image")) { + throw new ModelsError("provider", `Model ${model2.provider}/${model2.id} is not an image model`); + } +} +function assertClassifierModel(model2) { + if (!isModelType(model2, "classifier")) { + throw new ModelsError("provider", `Model ${model2.provider}/${model2.id} is not a classifier model`); + } +} +function assertClassifierInputSupported(model2, context) { + if (context.images?.length && !model2.input.includes("image")) { + throw new ModelsError("provider", `Model ${model2.provider}/${model2.id} does not accept image input`); + } +} +function imageErrorResult(model2, error, aborted = false) { + return { + api: model2.api, + provider: model2.provider, + model: model2.id, + output: [], + stopReason: aborted ? "aborted" : "error", + errorMessage: error instanceof Error ? error.message : String(error), + timestamp: Date.now() + }; +} +function classifierErrorResult(model2, error, aborted = false) { + return { + api: model2.api, + provider: model2.provider, + model: model2.id, + answers: {}, + stopReason: aborted ? "aborted" : "error", + errorMessage: error instanceof Error ? error.message : String(error), + timestamp: Date.now() + }; +} + +// node_modules/@earendil-works/pi-ai/dist/utils/transcript.js +function createInitialSystemMessage(systemPrompt, tools) { + const hasSystemPrompt = systemPrompt !== void 0 && systemPrompt.length > 0; + const hasTools = tools !== void 0 && tools.length > 0; + if (!hasSystemPrompt && !hasTools) + return void 0; + return { + role: "system", + content: systemPrompt ?? "", + ...hasTools ? { toolsAdded: tools } : {}, + timestamp: 0 + }; +} +function normalizeContext(context) { + const initialMessage = createInitialSystemMessage(context.systemPrompt, context.tools); + const messages = initialMessage ? [initialMessage, ...context.messages] : context.messages; + return { messages }; +} +function isSystemMessage(message) { + return message.role === "system"; +} +function getCurrentTools(messages) { + const tools = /* @__PURE__ */ new Map(); + for (const message of messages) { + if (!isSystemMessage(message)) + continue; + for (const tool of message.toolsRemoved ?? []) + tools.delete(tool.name); + for (const tool of message.toolsAdded ?? []) + tools.set(tool.name, tool); + } + return [...tools.values()]; +} +function toToolDeclaration(tool) { + return { + name: tool.name, + description: tool.description, + parameters: JSON.parse(JSON.stringify(tool.parameters)), + ...tool.constrainedSampling === void 0 ? {} : { constrainedSampling: tool.constrainedSampling } + }; +} +function declarationsEqual(left, right) { + return JSON.stringify(toToolDeclaration(left)) === JSON.stringify(toToolDeclaration(right)); +} + +// node_modules/@earendil-works/pi-ai/dist/models.js +var KNOWN_MODEL_TYPES = { chat: true, image: true, classifier: true }; +function hasKnownModelType(model2) { + return Object.hasOwn(KNOWN_MODEL_TYPES, getModelType(model2)); +} +function withKnownModelTypes(entry2) { + return { ...entry2, models: entry2.models.filter(hasKnownModelType) }; +} +function mergeHeaders(base, override) { + if (!base && !override) + return void 0; + const merged = { ...base }; + for (const [name, value2] of Object.entries(override ?? {})) { + const lowerName = name.toLowerCase(); + for (const existingName of Object.keys(merged)) { + if (existingName.toLowerCase() === lowerName) + delete merged[existingName]; + } + merged[name] = value2; + } + return merged; +} +var ModelsImpl = class { + providers = /* @__PURE__ */ new Map(); + credentials; + modelsStore; + authContext; + identity; + refreshGenerations = /* @__PURE__ */ new Map(); + refreshControllers = /* @__PURE__ */ new Map(); + publicationChains = /* @__PURE__ */ new Map(); + constructor(options) { + this.credentials = options?.credentials ?? new InMemoryCredentialStore(); + this.modelsStore = options?.modelsStore ?? new InMemoryModelsStore(); + this.authContext = options?.authContext ?? defaultProviderAuthContext(); + this.identity = options?.identity; + } + setProvider(provider2) { + this.supersedeProviderRefresh(provider2.id); + this.providers.set(provider2.id, provider2); + } + deleteProvider(id) { + this.supersedeProviderRefresh(id); + this.providers.delete(id); + } + clearProviders() { + for (const id of /* @__PURE__ */ new Set([...this.providers.keys(), ...this.refreshControllers.keys()])) { + this.supersedeProviderRefresh(id); + } + this.providers.clear(); + } + getProviders() { + return Array.from(this.providers.values()); + } + getProvider(id) { + return this.providers.get(id); + } + getModels(provider2) { + if (provider2 !== void 0) { + const entry2 = this.providers.get(provider2); + if (!entry2) + return []; + try { + return entry2.getModels(); + } catch { + return []; + } + } + const models2 = []; + for (const entry2 of this.providers.values()) { + try { + models2.push(...entry2.getModels()); + } catch { + } + } + return models2; + } + getAllModels(provider2) { + if (provider2 !== void 0) { + const entry2 = this.providers.get(provider2); + if (!entry2) + return []; + try { + return entry2.getAllModels?.() ?? entry2.getModels(); + } catch { + return []; + } + } + const models2 = []; + for (const entry2 of this.providers.values()) { + try { + models2.push(...entry2.getAllModels?.() ?? entry2.getModels()); + } catch { + } + } + return models2; + } + getModelsOfType(type, provider2) { + return this.getAllModels(provider2).filter((model2) => isModelType(model2, type)); + } + getModel(provider2, id) { + return this.getModels(provider2).find((model2) => model2.id === id); + } + getModelOfType(type, provider2, id) { + return this.getModelsOfType(type, provider2).find((model2) => model2.id === id); + } + supersedeProviderRefresh(providerId) { + const generation = (this.refreshGenerations.get(providerId) ?? 0) + 1; + this.refreshGenerations.set(providerId, generation); + const previous = this.refreshControllers.get(providerId); + if (previous) { + this.refreshControllers.delete(providerId); + previous.abort(); + } + return generation; + } + beginProviderRefresh(providerId) { + const generation = this.supersedeProviderRefresh(providerId); + const controller = new AbortController(); + this.refreshControllers.set(providerId, controller); + return { generation, controller }; + } + publishProviderModels(providerId, generation, signal, publication) { + const previous = this.publicationChains.get(providerId) ?? Promise.resolve(); + const queued = (async () => { + await previous.catch(() => { + }); + if (signal.aborted || this.refreshGenerations.get(providerId) !== generation) + return false; + if (publication.persist === null) { + await this.modelsStore.delete(providerId, { signal }); + } else if (publication.persist !== void 0) { + await this.modelsStore.write(providerId, structuredClone(publication.persist), { signal }); + } + if (signal.aborted || this.refreshGenerations.get(providerId) !== generation) + return false; + publication.update?.(); + return true; + })(); + const tail = queued.catch(() => { + }); + this.publicationChains.set(providerId, tail); + void tail.then(() => { + if (this.publicationChains.get(providerId) === tail) + this.publicationChains.delete(providerId); + }); + return raceWithAbortSignal(queued, signal); + } + async runProviderRefreshPhase(provider2, credential, allowNetwork, force, generation, signal) { + const stored = await this.modelsStore.read(provider2.id, { signal }); + await provider2.refreshModels({ + credential, + stored: stored ? withKnownModelTypes(structuredClone(stored)) : void 0, + publish: (publication) => this.publishProviderModels(provider2.id, generation, signal, publication), + allowNetwork, + force: allowNetwork ? force : void 0, + signal, + baseUrl: provider2.baseUrl + }); + } + async refresh(options = {}) { + const allowNetwork = options.allowNetwork ?? true; + const callerSignal = operationSignal(options.signal); + const errors = /* @__PURE__ */ new Map(); + if (callerSignal.aborted) + return { aborted: true, errors }; + const selected = options.providers ? new Set(options.providers) : void 0; + const refreshable = Array.from(this.providers.values()).filter((provider2) => provider2.refreshModels !== void 0 && (!selected || selected.has(provider2.id))); + const refresh = Promise.all(refreshable.map(async (provider2) => { + const { generation, controller } = this.beginProviderRefresh(provider2.id); + const signal = AbortSignal.any([callerSignal, controller.signal]); + const operation = (async () => { + let storedCredential; + let credentialError; + try { + storedCredential = await this.readCredential(provider2.id, signal); + } catch (error) { + credentialError = error; + } + await this.runProviderRefreshPhase(provider2, storedCredential, false, void 0, generation, signal); + if (credentialError !== void 0) + throw credentialError; + if (!allowNetwork || signal.aborted) + return; + const credential = await this.resolveRefreshCredential(provider2, storedCredential, signal); + if (!credential) + return; + await this.runProviderRefreshPhase(provider2, credential, true, options.force, generation, signal); + })(); + try { + await raceWithAbortSignal(operation, signal); + } catch (error) { + if (!signal.aborted) { + errors.set(provider2.id, error instanceof Error ? error : new ModelsError("model_source", `Model refresh failed for ${provider2.id}`, { cause: error })); + } + } finally { + if (this.refreshControllers.get(provider2.id) === controller) { + this.refreshControllers.delete(provider2.id); + } + } + })); + try { + await raceWithAbortSignal(refresh, callerSignal); + } catch (error) { + if (!callerSignal.aborted) + throw error; + } + return { aborted: callerSignal.aborted, errors: new Map(errors) }; + } + async resolveRefreshCredential(provider2, stored, signal) { + if (stored?.type === "oauth") { + const oauth = provider2.auth.oauth; + if (!oauth) + return void 0; + if (Date.now() < stored.expires) + return stored; + if (signal.aborted) + return void 0; + return refreshStoredOAuthCredential(this.credentials, provider2.id, oauth, (current) => Date.now() >= current.expires, signal); + } + const apiKey = provider2.auth.apiKey; + if (!apiKey) + return void 0; + const credential = stored?.type === "api_key" ? stored : void 0; + const result = await apiKey.resolve({ ctx: this.authContext, credential, signal }); + if (!result) + return void 0; + return { type: "api_key", key: result.auth.apiKey, env: result.env }; + } + async readCredential(providerId, signal) { + try { + return await this.credentials.read(providerId, { signal }); + } catch (error) { + throw new ModelsError("auth", `Credential store read failed for ${providerId}`, { cause: error }); + } + } + async checkProviderAuth(provider2, credential, signal) { + if (credential?.type === "oauth") { + return provider2.auth.oauth ? { source: "OAuth", type: "oauth" } : void 0; + } + const apiKey = provider2.auth.apiKey; + if (!apiKey) + return void 0; + if (apiKey.check) { + try { + return await apiKey.check({ + ctx: this.authContext, + credential: credential?.type === "api_key" ? credential : void 0, + signal + }); + } catch (error) { + throw new ModelsError("auth", `API key auth check failed for provider ${provider2.id}`, { cause: error }); + } + } + const resolution = await resolveProviderAuth(provider2, this.credentials, this.authContext, { signal }); + return resolution ? { source: resolution.source, type: "api_key" } : void 0; + } + checkAuth(providerId, options) { + const signal = operationSignal(options?.signal); + const check = (async () => { + signal.throwIfAborted(); + const provider2 = this.providers.get(providerId); + if (!provider2) + return void 0; + return this.checkProviderAuth(provider2, await this.readCredential(providerId, signal), signal); + })(); + return raceWithAbortSignal(check, signal); + } + async getAuthenticatedProviders(providerId, signal) { + signal.throwIfAborted(); + const providers = providerId ? [this.providers.get(providerId)].filter((entry2) => entry2 !== void 0) : this.getProviders(); + const checks = await Promise.all(providers.map(async (provider2) => { + const credential = await this.readCredential(provider2.id, signal); + return { provider: provider2, credential, auth: await this.checkProviderAuth(provider2, credential, signal) }; + })); + return checks.filter((entry2) => entry2.auth !== void 0); + } + getAvailable(providerId, options) { + const signal = operationSignal(options?.signal); + const available = (async () => { + const providers = await this.getAuthenticatedProviders(providerId, signal); + return providers.flatMap(({ provider: provider2, credential }) => { + const models2 = provider2.getModels(); + return provider2.filterModels?.(models2, credential) ?? models2; + }); + })(); + return raceWithAbortSignal(available, signal); + } + async getAvailableOfType(type, providerId, options) { + return (await this.getAllAvailable(providerId, options)).filter((model2) => isModelType(model2, type)); + } + getAllAvailable(providerId, options) { + const signal = operationSignal(options?.signal); + const available = (async () => { + const providers = await this.getAuthenticatedProviders(providerId, signal); + return providers.flatMap(({ provider: provider2, credential }) => { + const models2 = provider2.getAllModels?.() ?? provider2.getModels(); + if (provider2.filterAllModels) + return provider2.filterAllModels(models2, credential); + if (!provider2.filterModels) + return models2; + const availableChatIds = new Set(provider2.filterModels(provider2.getModels(), credential).map((model2) => model2.id)); + return models2.filter((model2) => !isModelType(model2, "chat") || availableChatIds.has(model2.id)); + }); + })(); + return raceWithAbortSignal(available, signal); + } + async getAuth(providerOrModel, overrides) { + const signal = operationSignal(overrides?.signal); + const providerId = typeof providerOrModel === "string" ? providerOrModel : providerOrModel.provider; + const provider2 = this.providers.get(providerId); + if (!provider2) + return void 0; + const result = await resolveProviderAuth(provider2, this.credentials, this.authContext, { ...overrides, signal }); + if (!result || typeof providerOrModel === "string" || !providerOrModel.headers) + return result; + return { + ...result, + auth: { + ...result.auth, + headers: mergeHeaders(result.auth.headers, providerOrModel.headers) + } + }; + } + async login(providerId, type, interaction, options) { + const signal = operationSignal(interaction.signal); + signal.throwIfAborted(); + const provider2 = this.providers.get(providerId); + if (!provider2) + throw new ModelsError("provider", `Unknown provider: ${providerId}`); + const method = type === "oauth" ? provider2.auth.oauth : provider2.auth.apiKey; + if (!method?.login) { + throw new ModelsError("auth", `${provider2.name} does not support ${type} login`); + } + const loginOperation = method.login({ ...interaction, signal }, options); + const credential = await raceWithAbortSignal(loginOperation, signal); + let mutationStarted = false; + let markMutationStarted; + const started = new Promise((resolve2) => { + markMutationStarted = resolve2; + }); + const mutation = this.credentials.modify(providerId, async () => { + mutationStarted = true; + markMutationStarted?.(); + return credential; + }, { signal }); + void mutation.catch(() => { + }); + try { + await new Promise((resolve2, reject2) => { + const onAbort = () => { + if (!mutationStarted) + reject2(signal.reason); + }; + signal.addEventListener("abort", onAbort, { once: true }); + void Promise.race([started, mutation]).then(() => { + signal.removeEventListener("abort", onAbort); + resolve2(); + }, (error) => { + signal.removeEventListener("abort", onAbort); + reject2(error); + }); + if (signal.aborted) + onAbort(); + }); + await mutation; + } catch (error) { + signal.throwIfAborted(); + throw new ModelsError("auth", `Credential store modify failed for ${providerId}`, { cause: error }); + } + return credential; + } + async logout(providerId, options) { + const signal = operationSignal(options?.signal); + signal.throwIfAborted(); + try { + await this.credentials.delete(providerId, { signal }); + } catch (error) { + signal.throwIfAborted(); + throw new ModelsError("auth", `Credential store delete failed for ${providerId}`, { cause: error }); + } + } + requireProvider(model2) { + const provider2 = this.providers.get(model2.provider); + if (!provider2) { + throw new ModelsError("provider", `Unknown provider: ${model2.provider}`); + } + return provider2; + } + requireChatProvider(model2) { + assertChatModel(model2); + return this.requireProvider(model2); + } + async applyAuth(model2, options) { + this.requireProvider(model2); + const resolution = await this.getAuth(model2, { + apiKey: options?.apiKey, + env: options?.env, + signal: options?.signal + }); + if (!resolution) { + throw new ModelsError("auth", `Provider is not configured: ${model2.provider}`); + } + const auth = resolution.auth; + const apiKey = options?.apiKey ?? auth.apiKey; + const requestModel = auth.baseUrl ? { ...model2, baseUrl: auth.baseUrl } : model2; + const sessionId = options && "sessionId" in options && typeof options.sessionId === "string" ? options.sessionId : void 0; + let headers = mergeHeaders(mergeHeaders(getOpenCodeSessionHeaders(requestModel, sessionId), auth.headers), options?.headers); + if (options?.transformHeaders) + headers = await options.transformHeaders(headers ?? {}); + const env = resolution.env || options?.env ? { ...resolution.env ?? {}, ...options?.env ?? {} } : void 0; + const identity = mergeClientIdentity(this.identity, options?.identity); + const { transformHeaders: _transformHeaders, ...providerOptions } = options ?? {}; + const requestOptions = { + ...providerOptions, + apiKey, + headers, + env, + ...identity === void 0 ? {} : { identity } + }; + return { requestModel, requestOptions }; + } + stream(model2, context, options) { + const transcript = normalizeContext(context); + return lazyStream(model2, async () => { + const provider2 = this.requireChatProvider(model2); + const { requestModel, requestOptions } = await this.applyAuth(model2, options); + return provider2.stream(requestModel, transcript, requestOptions); + }, observeModelRequest(model2, options, false)); + } + async complete(model2, context, options) { + return this.stream(model2, context, options).result(); + } + streamSimple(model2, context, options) { + const transcript = normalizeContext(context); + return lazyStream(model2, async () => { + const provider2 = this.requireChatProvider(model2); + const { requestModel, requestOptions } = await this.applyAuth(model2, options); + return provider2.streamSimple(requestModel, transcript, requestOptions); + }, observeModelRequest(model2, options, false)); + } + async completeSimple(model2, context, options) { + return this.streamSimple(model2, context, options).result(); + } + streamDeferred(model2, handle, options) { + return lazyStream(model2, async () => { + const provider2 = this.requireChatProvider(model2); + if (!provider2.fetchDeferred) { + throw new ModelsError("provider", `Provider ${model2.provider} does not support deferred responses`); + } + const { requestModel, requestOptions } = await this.applyAuth(model2, options); + return provider2.fetchDeferred(requestModel, handle, requestOptions); + }, observeModelRequest(model2, options, true)); + } + async fetchDeferred(model2, handle, options) { + return this.streamDeferred(model2, handle, options).result(); + } + async cancelDeferred(model2, handle, options) { + const provider2 = this.requireChatProvider(model2); + if (!provider2.cancelDeferred) { + throw new ModelsError("provider", `Provider ${model2.provider} does not support deferred responses`); + } + const { requestModel, requestOptions } = await this.applyAuth(model2, options); + await provider2.cancelDeferred(requestModel, handle, requestOptions); + } + async generateImages(model2, context, options) { + try { + assertImageModel(model2); + const provider2 = this.requireProvider(model2); + if (!provider2.generateImages) { + throw new ModelsError("provider", `Provider ${model2.provider} does not support image generation`); + } + const { requestModel, requestOptions } = await this.applyAuth(model2, options); + return await provider2.generateImages(requestModel, context, requestOptions); + } catch (error) { + return imageErrorResult(model2, error, options?.signal?.aborted); + } + } + async classify(model2, context, options) { + try { + assertClassifierModel(model2); + assertClassifierInputSupported(model2, context); + const provider2 = this.requireProvider(model2); + if (!provider2.classify) { + throw new ModelsError("provider", `Provider ${model2.provider} does not support classification`); + } + const { requestModel, requestOptions } = await this.applyAuth(model2, options); + return await provider2.classify(requestModel, context, requestOptions); + } catch (error) { + return classifierErrorResult(model2, error, options?.signal?.aborted); + } + } +}; +function createModels(options) { + return new ModelsImpl(options); +} +function createProvider(input) { + const single = input.api && typeof input.api.stream === "function" ? input.api : void 0; + const byApi = single || !input.api ? void 0 : input.api; + const images = input.images; + const classifiers = input.classifiers; + const streams = single ? [single] : Object.values(byApi ?? {}).filter((entry2) => entry2 !== void 0); + const imageImplementations = Object.values(images ?? {}).filter((entry2) => entry2 !== void 0); + const classifierImplementations = Object.values(classifiers ?? {}).filter((entry2) => entry2 !== void 0); + if (streams.length === 0 && imageImplementations.length === 0 && classifierImplementations.length === 0) { + throw new Error(`Provider ${input.id}: at least one of "api", "images", or "classifiers" is required.`); + } + const baselineModels = input.models; + let dynamicModels = []; + const fetchModels = input.fetchModels; + const currentModels2 = () => { + const merged = [...baselineModels]; + for (const model2 of dynamicModels) { + const index = merged.findIndex((entry2) => getModelType(entry2) === getModelType(model2) && entry2.id === model2.id); + if (index >= 0) + merged[index] = model2; + else + merged.push(model2); + } + return merged; + }; + const apiFor = (model2) => single ?? byApi?.[model2.api]; + const dispatch = (model2, run2) => { + const streams2 = apiFor(model2); + if (!streams2) { + return lazyStream(model2, async () => { + throw new ModelsError("stream", `Provider ${input.id} has no API implementation for "${model2.api}"`); + }); + } + return run2(streams2); + }; + const provider2 = { + id: input.id, + name: input.name ?? input.id, + baseUrl: input.baseUrl, + headers: input.headers, + auth: input.auth, + getModels: () => currentModels2().filter((model2) => isModelType(model2, "chat")), + getAllModels: currentModels2, + refreshModels: fetchModels ? async (context) => { + if (context.stored) { + const restored = context.stored.models.filter((model2) => model2.provider === input.id).map((model2) => model2); + if (!await context.publish({ + update: () => { + dynamicModels = restored; + } + })) { + return; + } + } + if (!context.allowNetwork || context.signal.aborted) + return; + const fetched = await fetchModels(context); + if (context.signal.aborted) + return; + const refreshed = fetched.filter(hasKnownModelType); + await context.publish({ + persist: { models: refreshed, checkedAt: Date.now() }, + update: () => { + dynamicModels = refreshed; + } + }); + } : void 0, + filterModels: input.filterModels, + filterAllModels: input.filterAllModels, + stream: (model2, context, options) => dispatch(model2, (streams2) => streams2.stream(model2, context, options)), + streamSimple: (model2, context, options) => dispatch(model2, (streams2) => streams2.streamSimple(model2, context, options)) + }; + if (streams.some((entry2) => entry2.fetchDeferred !== void 0)) { + provider2.fetchDeferred = (model2, handle, options) => lazyStream(model2, async () => { + const implementation = apiFor(model2); + if (!implementation?.fetchDeferred) { + throw new ModelsError("provider", `Provider ${input.id} does not support deferred responses for "${model2.api}"`); + } + return implementation.fetchDeferred(model2, handle, options); + }); + } + if (streams.some((entry2) => entry2.cancelDeferred !== void 0)) { + provider2.cancelDeferred = async (model2, handle, options) => { + const implementation = apiFor(model2); + if (!implementation?.cancelDeferred) { + throw new ModelsError("provider", `Provider ${input.id} cannot cancel deferred responses for "${model2.api}"`); + } + await implementation.cancelDeferred(model2, handle, options); + }; + } + if (images && imageImplementations.length > 0) { + provider2.generateImages = async (model2, context, options) => { + const implementation = images[model2.api]; + if (!implementation) { + return imageErrorResult(model2, new ModelsError("provider", `Provider ${input.id} has no image generation implementation for "${model2.api}"`)); + } + return implementation.generateImages(model2, context, options); + }; + } + if (classifiers && classifierImplementations.length > 0) { + provider2.classify = async (model2, context, options) => { + const implementation = classifiers[model2.api]; + if (!implementation) { + return classifierErrorResult(model2, new ModelsError("provider", `Provider ${input.id} has no classifier implementation for "${model2.api}"`)); + } + return implementation.classify(model2, context, options); + }; + } + return provider2; +} + +// node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js +var import_partial_json = __toESM(require_dist(), 1); +var VALID_JSON_ESCAPES = /* @__PURE__ */ new Set(['"', "\\", "/", "b", "f", "n", "r", "t"]); +function isControlCharacter(char) { + const codePoint = char.codePointAt(0); + return codePoint !== void 0 && codePoint >= 0 && codePoint <= 31; +} +function escapeControlCharacter(char) { + switch (char) { + case "\b": + return "\\b"; + case "\f": + return "\\f"; + case "\n": + return "\\n"; + case "\r": + return "\\r"; + case " ": + return "\\t"; + default: + return `\\u${char.codePointAt(0)?.toString(16).padStart(4, "0") ?? "0000"}`; + } +} +function repairJson(json) { + let repaired = ""; + let inString = false; + for (let index = 0; index < json.length; index++) { + const char = json[index]; + if (!inString) { + repaired += char; + if (char === '"') { + inString = true; + } + continue; + } + if (char === '"') { + repaired += char; + inString = false; + continue; + } + if (char === "\\") { + const nextChar = json[index + 1]; + if (nextChar === void 0) { + repaired += "\\\\"; + continue; + } + if (nextChar === "u") { + const unicodeDigits = json.slice(index + 2, index + 6); + if (/^[0-9a-fA-F]{4}$/.test(unicodeDigits)) { + repaired += `\\u${unicodeDigits}`; + index += 5; + continue; + } + } + if (VALID_JSON_ESCAPES.has(nextChar)) { + repaired += `\\${nextChar}`; + index += 1; + continue; + } + repaired += "\\\\"; + continue; + } + repaired += isControlCharacter(char) ? escapeControlCharacter(char) : char; + } + return repaired; +} +function parseJsonWithRepair(json) { + try { + return JSON.parse(json); + } catch (error) { + const repairedJson = repairJson(json); + if (repairedJson !== json) { + return JSON.parse(repairedJson); + } + throw error; + } +} +function parseToolCallArguments(json) { + if (!json?.trim()) + return { arguments: {} }; + try { + const parsed = parseJsonWithRepair(json); + if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) { + throw new Error("Tool arguments must be a JSON object"); + } + return { arguments: parsed }; + } catch (error) { + return { + arguments: {}, + argumentsError: `${error instanceof Error ? error.message : String(error)} + +Received arguments: +${json}` + }; + } +} + +// node_modules/@earendil-works/pi-ai/dist/utils/streaming-json.js +var MAX_REPORTED_DEPTH = 32; +var ROOT_SLOT = { kind: "root" }; +var CREDIT_PER_APPEND = 256; +var CREDIT_PER_CHARACTER = 8; +var MAX_PENDING_SCALAR_LENGTH = 64; +var NUMBER = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/; +var NUMBER_WITHOUT_EXPONENT_DIGITS = /^(-?(?:0|[1-9]\d*)(?:\.\d+)?)[eE][+-]?$/; +var LITERALS = [ + ["true", true], + ["false", false], + ["null", null] +]; +var QUOTE = 34; +var BACKSLASH = 92; +var StreamingJsonParser = class { + #root = void 0; + #done = false; + #stack = []; + #string = void 0; + #scalar = ""; + #scalarSlot = void 0; + /** Sum of `size + 1` over the open path: what a fresh snapshot copies. */ + #pathCost = 0; + #credit = 0; + #dirty = false; + #snapshot = void 0; + /** Changes of the piece being read. */ + #changes = []; + /** + * Read the next piece of text; returns the changes it made, in order. Costs time linear in `text.length`. + */ + append(text) { + this.#credit += CREDIT_PER_APPEND + CREDIT_PER_CHARACTER * text.length; + this.#changes = []; + if (this.#string !== void 0) + this.#string.change = void 0; + let index = 0; + while (index < text.length && !this.#done) { + const open = this.#string; + if (open !== void 0) + index = this.#readString(open, text, index); + else if (this.#scalar !== "") + index = this.#readScalar(text, index); + else + this.#structural(text[index++]); + } + return this.#changes; + } + /** + * The value of the text read so far: `undefined` before a value starts, otherwise a plain JSON value that never + * changes afterwards. Returns the previous snapshot while the text read since did not change the value, or while a + * fresh copy of the open path is not yet paid for (see the module comment). + */ + snapshot() { + if (!this.#dirty) + return this.#snapshot; + const pending = this.#pendingScalar(); + const cost = this.#pathCost + (pending === void 0 ? 0 : 1); + if (cost > this.#credit) + return this.#snapshot; + this.#credit -= cost; + this.#dirty = false; + this.#snapshot = this.#copyOpenPath(pending); + return this.#snapshot; + } + /** Read string characters from `start` until the string ends or the text does; returns the next index. */ + #readString(open, text, start) { + let runStart = start; + for (let index = start; index < text.length; index++) { + const code = text.charCodeAt(index); + if (open.escape !== "") { + if (this.#continueEscape(open, text[index])) { + runStart = index + 1; + continue; + } + runStart = index; + } + if (code === QUOTE) { + if (index > runStart) + this.#appendString(open, text.slice(runStart, index)); + this.#endString(open); + return index + 1; + } + if (code === BACKSLASH) { + if (index > runStart) + this.#appendString(open, text.slice(runStart, index)); + open.escape = "\\"; + runStart = index + 1; + } + } + if (text.length > runStart) + this.#appendString(open, text.slice(runStart)); + return text.length; + } + /** Read number or literal characters from `start` up to the next delimiter; returns the delimiter's index. */ + #readScalar(text, start) { + let end = start; + while (end < text.length && !isDelimiter(text[end])) + end++; + if (end > start) { + this.#scalar += text.slice(start, end); + if (this.#scalarSlot !== void 0) + this.#dirty = true; + } + if (end < text.length) + this.#endScalar(); + return end; + } + /** Handle one character outside strings. */ + #structural(char) { + switch (char) { + case " ": + case " ": + case "\n": + case "\r": + return; + case '"': + this.#startString(); + return; + case "{": + case "[": + this.#openContainer(char === "{" ? {} : []); + return; + case "}": + case "]": + this.#closeContainer(); + return; + case ":": { + const frame = this.#stack.at(-1); + if (frame !== void 0 && !Array.isArray(frame.container) && frame.phase === "colon") + frame.phase = "value"; + return; + } + case ",": { + const frame = this.#stack.at(-1); + if (frame !== void 0) + frame.phase = Array.isArray(frame.container) ? "value" : "key"; + return; + } + default: + this.#scalar = char; + this.#scalarSlot = this.#valueSlot(); + if (this.#scalarSlot !== void 0) + this.#dirty = true; + } + } + /** Where a value starting now goes, or `undefined` when this position takes no value. */ + #valueSlot() { + const frame = this.#stack.at(-1); + if (frame === void 0) + return this.#root === void 0 ? ROOT_SLOT : void 0; + if (Array.isArray(frame.container)) + return { kind: "element", index: frame.container.length }; + if ((frame.phase === "value" || frame.phase === "colon") && frame.key !== void 0) { + return { kind: "member", key: frame.key }; + } + return void 0; + } + #startString() { + const frame = this.#stack.at(-1); + if (frame !== void 0 && !Array.isArray(frame.container) && (frame.phase === "key" || frame.phase === "comma")) { + this.#string = { target: "key", slot: void 0, text: "", escape: "", path: void 0, change: void 0 }; + return; + } + const slot = this.#valueSlot(); + const path = this.#reportedPath(slot); + this.#string = { target: "value", slot, text: "", escape: "", path, change: void 0 }; + this.#place(slot, ""); + if (path !== void 0) + this.#string.change = this.#report({ kind: "set", path, value: "" }); + } + /** The path of a value at `slot` in the innermost open container, when its changes are reported. */ + #reportedPath(slot) { + if (slot === void 0) + return void 0; + if (slot.kind === "root") + return []; + const frame = this.#stack.at(-1); + if (!frame.reportsInside) + return void 0; + return [...frame.path, slot.kind === "member" ? slot.key : slot.index]; + } + #report(change) { + this.#changes.push(change); + return change; + } + /** Continue an escape with `char`; returns false when `char` is not part of it and must be read normally. */ + #continueEscape(open, char) { + if (open.escape === "\\") { + const decoded = SIMPLE_ESCAPES[char]; + if (decoded !== void 0) { + open.escape = ""; + this.#appendString(open, decoded); + return true; + } + if (char === "u") { + open.escape = "\\u"; + return true; + } + open.escape = ""; + this.#appendString(open, "\\"); + return false; + } + if (isHexDigit(char)) { + open.escape += char; + if (open.escape.length < 6) + return true; + const decoded = String.fromCharCode(Number.parseInt(open.escape.slice(2), 16)); + open.escape = ""; + this.#appendString(open, decoded); + return true; + } + const literal = open.escape; + open.escape = ""; + this.#appendString(open, literal); + return false; + } + #appendString(open, text) { + open.text += text; + if (open.target !== "value") + return; + this.#place(open.slot, open.text); + if (open.path === void 0) + return; + const change = open.change; + if (change !== void 0 && this.#changes.at(-1) === change) { + if (change.kind === "set") + change.value = change.value + text; + else + change.text += text; + return; + } + open.change = this.#report({ kind: "append", path: open.path, text }); + } + #endString(open) { + this.#string = void 0; + const frame = this.#stack.at(-1); + if (open.target === "key") { + if (frame === void 0) + return; + frame.key = open.text; + frame.phase = "colon"; + return; + } + this.#valueEnded(frame); + } + #endScalar() { + const token = this.#scalar; + const slot = this.#scalarSlot; + this.#scalar = ""; + this.#scalarSlot = void 0; + const value2 = scalarValue(token); + if (value2 !== void 0) { + this.#place(slot, value2); + const path = this.#reportedPath(slot); + if (path !== void 0) + this.#report({ kind: "set", path, value: value2 }); + } + this.#valueEnded(this.#stack.at(-1)); + } + /** The value of the unterminated scalar at the end of the text, if it shows. */ + #pendingScalar() { + const slot = this.#scalarSlot; + const token = this.#scalar; + if (slot === void 0 || token === "" || token.length > MAX_PENDING_SCALAR_LENGTH) + return void 0; + const value2 = pendingScalarValue(token); + return value2 === void 0 ? void 0 : { slot, value: value2 }; + } + #openContainer(container) { + const slot = this.#valueSlot(); + const path = this.#reportedPath(slot); + this.#place(slot, container); + this.#stack.push({ + container, + slot, + path, + reportsInside: path !== void 0 && path.length < MAX_REPORTED_DEPTH, + size: 0, + key: void 0, + phase: Array.isArray(container) ? "value" : "key" + }); + this.#pathCost += 1; + this.#dirty = true; + if (path !== void 0) + this.#report({ kind: "set", path, value: Array.isArray(container) ? [] : {} }); + } + #closeContainer() { + const frame = this.#stack.pop(); + if (frame === void 0) + return; + this.#pathCost -= frame.size + 1; + this.#dirty = true; + if (frame.path !== void 0 && !frame.reportsInside) { + this.#report({ kind: "set", path: frame.path, value: frame.container }); + } + this.#valueEnded(this.#stack.at(-1)); + } + /** A value in `frame`, or the root value when there is no frame, has ended. */ + #valueEnded(frame) { + if (frame === void 0) { + if (this.#root !== void 0) + this.#done = true; + return; + } + frame.phase = "comma"; + } + /** Set the value at `slot` in the open path; nothing for a value in an invalid position. */ + #place(slot, value2) { + if (slot === void 0) + return; + this.#dirty = true; + if (slot.kind === "root") { + this.#root = value2; + return; + } + const frame = this.#stack.at(-1); + if (slot.kind === "element") { + const elements = frame.container; + if (slot.index === elements.length) { + frame.size++; + this.#pathCost++; + } + elements[slot.index] = value2; + return; + } + const members = frame.container; + if (!Object.hasOwn(members, slot.key)) { + frame.size++; + this.#pathCost++; + } + setMember(members, slot.key, value2); + } + /** A fresh snapshot: copies of the open containers, innermost first, each holding the copy of its open child. */ + #copyOpenPath(pending) { + if (this.#stack.length === 0) + return pending?.slot.kind === "root" ? pending.value : this.#root; + let child; + let childSlot; + for (let depth = this.#stack.length - 1; depth >= 0; depth--) { + const frame = this.#stack[depth]; + const copy2 = Array.isArray(frame.container) ? frame.container.slice() : { ...frame.container }; + if (depth === this.#stack.length - 1 && pending !== void 0) + setSlot(copy2, pending.slot, pending.value); + if (child !== void 0 && childSlot !== void 0) + setSlot(copy2, childSlot, child); + child = copy2; + childSlot = frame.slot; + } + return childSlot?.kind === "root" ? child : this.#root; + } +}; +var ToolCallArgumentsStream = class { + #text = ""; + #parser = new StreamingJsonParser(); + #snapshot = void 0; + #arguments = {}; + /** The raw argument text received so far. */ + get text() { + return this.#text; + } + /** Append a piece of argument text; returns the partial arguments, a new object whenever they changed. */ + append(delta) { + this.#text += delta; + this.#parser.append(delta); + return this.#partial(); + } + /** + * Take the provider's complete argument text. When it continues the text so far, returns the missing piece as + * `delta`; otherwise starts over with `text`. Either way returns the partial arguments of `text`. + */ + replace(text) { + if (text.startsWith(this.#text)) { + const delta = text.slice(this.#text.length); + return { delta, arguments: delta === "" ? this.#partial() : this.append(delta) }; + } + this.#text = ""; + this.#parser = new StreamingJsonParser(); + return { delta: void 0, arguments: this.append(text) }; + } + /** The final arguments: one full parse of the complete text, which reports malformed arguments. */ + finish() { + return parseToolCallArguments(this.#text); + } + #partial() { + const snapshot = this.#parser.snapshot(); + if (snapshot === this.#snapshot) + return this.#arguments; + this.#snapshot = snapshot; + this.#arguments = typeof snapshot === "object" && snapshot !== null && !Array.isArray(snapshot) ? snapshot : {}; + return this.#arguments; + } +}; +var SIMPLE_ESCAPES = { + '"': '"', + "\\": "\\", + "/": "/", + b: "\b", + f: "\f", + n: "\n", + r: "\r", + t: " " +}; +function isDelimiter(char) { + return char === " " || char === " " || char === "\n" || char === "\r" || char === "," || char === ":" || char === "{" || char === "}" || char === "[" || char === "]" || char === '"'; +} +function isHexDigit(char) { + return char >= "0" && char <= "9" || char >= "a" && char <= "f" || char >= "A" && char <= "F"; +} +function scalarValue(token) { + for (const [literal, value2] of LITERALS) + if (token === literal) + return value2; + return NUMBER.test(token) ? Number(token) : void 0; +} +function pendingScalarValue(token) { + for (const [literal, value2] of LITERALS) + if (literal.startsWith(token)) + return value2; + if (NUMBER.test(token)) + return Number(token); + const mantissa = NUMBER_WITHOUT_EXPONENT_DIGITS.exec(token); + return mantissa === null ? void 0 : Number(mantissa[1]); +} +function setSlot(container, slot, value2) { + if (slot.kind === "element") + container[slot.index] = value2; + else if (slot.kind === "member") + setMember(container, slot.key, value2); +} +function setMember(members, key, value2) { + if (key === "__proto__") { + Object.defineProperty(members, key, { value: value2, writable: true, enumerable: true, configurable: true }); + } else { + members[key] = value2; + } +} + +// node_modules/@earendil-works/pi-ai/dist/providers/faux.js +var DEFAULT_API = "faux"; +var DEFAULT_PROVIDER = "faux"; +var DEFAULT_MODEL_ID = "faux-1"; +var DEFAULT_MODEL_NAME = "Faux Model"; +var DEFAULT_BASE_URL = "http://localhost:0"; +var DEFAULT_MIN_TOKEN_SIZE = 3; +var DEFAULT_MAX_TOKEN_SIZE = 5; +var DEFAULT_USAGE = { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + totalTokens: 0, + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } +}; +function fauxText(text) { + return { type: "text", text }; +} +function normalizeFauxAssistantContent(content) { + if (typeof content === "string") { + return [fauxText(content)]; + } + return Array.isArray(content) ? content : [content]; +} +function fauxAssistantMessage(content, options = {}) { + return { + role: "assistant", + content: normalizeFauxAssistantContent(content), + api: DEFAULT_API, + provider: DEFAULT_PROVIDER, + model: DEFAULT_MODEL_ID, + usage: DEFAULT_USAGE, + stopReason: options.stopReason ?? "stop", + ...options.deferred === void 0 ? {} : { deferred: options.deferred }, + ...options.errorMessage === void 0 ? {} : { errorMessage: options.errorMessage }, + ...options.responseId === void 0 ? {} : { responseId: options.responseId }, + timestamp: options.timestamp ?? Date.now() + }; +} +function estimateTokens(text) { + return Math.ceil(text.length / 4); +} +function randomId(prefix) { + return `${prefix}:${Date.now()}:${Math.random().toString(36).slice(2)}`; +} +function contentToText(content) { + if (typeof content === "string") { + return content; + } + return content.map((block) => { + if (block.type === "text") { + return block.text; + } + return `[image:${block.mimeType}:${block.data.length}]`; + }).join("\n"); +} +function assistantContentToText(content) { + return content.map((block) => { + if (block.type === "text") { + return block.text; + } + if (block.type === "thinking") { + return block.thinking; + } + return `${block.name}:${JSON.stringify(block.arguments)}`; + }).join("\n"); +} +function toolResultToText(message) { + return [message.toolName, ...message.content.map((block) => contentToText([block]))].join("\n"); +} +function messageToText(message) { + if (message.role === "system") { + return [ + getSystemMessageText(message), + ...message.toolsRemoved?.map((tool) => `tool-:${JSON.stringify(tool)}`) ?? [], + ...message.toolsAdded?.map((tool) => `tool+:${JSON.stringify(tool)}`) ?? [] + ].filter((part) => part.length > 0).join("\n"); + } + if (message.role === "user") { + return contentToText(message.content); + } + if (message.role === "assistant") { + return assistantContentToText(message.content); + } + return toolResultToText(message); +} +function joinedLength(messages, count = messages.length) { + let length = count > 0 ? (count - 1) * 2 : 0; + for (let index = 0; index < count; index++) + length += messages[index].length; + return length; +} +function commonPromptPrefixLength(previous, current) { + let index = 0; + while (index < previous.length && index < current.length && previous[index] === current[index]) + index++; + const rest = (messages) => index === messages.length ? "" : (index > 0 ? "\n\n" : "") + messages.slice(index).join("\n\n"); + return joinedLength(previous, index) + commonPrefixLength(rest(previous), rest(current)); +} +function commonPrefixLength(a, b) { + const length = Math.min(a.length, b.length); + let index = 0; + while (index < length && a[index] === b[index]) { + index++; + } + return index; +} +function withUsageEstimate(message, context, options, promptCache) { + const prompt = context.messages.map((message2) => `${message2.role}:${messageToText(message2)}`); + const promptLength = joinedLength(prompt); + const promptTokens = Math.ceil(promptLength / 4); + const outputTokens = estimateTokens(assistantContentToText(message.content)); + let input = promptTokens; + let cacheRead = 0; + let cacheWrite = 0; + const sessionId = options?.sessionId; + if (sessionId && options?.cacheRetention !== "none") { + const previousPrompt = promptCache.get(sessionId); + if (previousPrompt) { + const cachedChars = commonPromptPrefixLength(previousPrompt, prompt); + cacheRead = Math.ceil(cachedChars / 4); + cacheWrite = Math.max(0, promptTokens - cacheRead); + } else { + cacheWrite = promptTokens; + } + input = 0; + promptCache.set(sessionId, prompt); + } + return { + ...message, + usage: { + input, + output: outputTokens, + cacheRead, + cacheWrite, + totalTokens: input + outputTokens + cacheRead + cacheWrite, + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } + } + }; +} +function splitStringByTokenSize(text, minTokenSize, maxTokenSize) { + const chunks = []; + let index = 0; + while (index < text.length) { + const tokenSize = minTokenSize + Math.floor(Math.random() * (maxTokenSize - minTokenSize + 1)); + const charSize = Math.max(1, tokenSize * 4); + chunks.push(text.slice(index, index + charSize)); + index += charSize; + } + return chunks.length > 0 ? chunks : [""]; +} +function cloneMessage(message, api, provider2, modelId) { + const cloned = structuredClone(message); + return { + ...cloned, + api, + provider: provider2, + model: modelId, + timestamp: cloned.timestamp ?? Date.now(), + usage: cloned.usage ?? DEFAULT_USAGE + }; +} +function createDeferredMessage(model2, handle) { + return { + role: "assistant", + content: [], + api: model2.api, + provider: model2.provider, + model: model2.id, + usage: DEFAULT_USAGE, + stopReason: "deferred", + deferred: handle, + timestamp: Date.now() + }; +} +function createErrorMessage(error, api, provider2, modelId) { + return { + role: "assistant", + content: [], + api, + provider: provider2, + model: modelId, + usage: DEFAULT_USAGE, + stopReason: "error", + errorMessage: error instanceof Error ? error.message : String(error), + timestamp: Date.now() + }; +} +function createAbortedMessage(partial) { + return { + ...partial, + stopReason: "aborted", + errorMessage: "Request was aborted", + timestamp: Date.now() + }; +} +function scheduleChunk(chunk, tokensPerSecond) { + if (!tokensPerSecond || tokensPerSecond <= 0) { + return new Promise((resolve2) => queueMicrotask(resolve2)); + } + const delayMs = estimateTokens(chunk) / tokensPerSecond * 1e3; + return new Promise((resolve2) => setTimeout(resolve2, delayMs)); +} +async function streamWithDeltas(stream, message, minTokenSize, maxTokenSize, tokensPerSecond, signal) { + const partial = { ...message, content: [], stopReason: "pending" }; + if (signal?.aborted) { + const aborted = createAbortedMessage(partial); + stream.push({ type: "error", reason: "aborted", error: aborted }); + stream.end(aborted); + return; + } + stream.push({ type: "start", partial: { ...partial } }); + for (let index = 0; index < message.content.length; index++) { + if (signal?.aborted) { + const aborted = createAbortedMessage(partial); + stream.push({ type: "error", reason: "aborted", error: aborted }); + stream.end(aborted); + return; + } + const block = message.content[index]; + if (block.type === "thinking") { + partial.content = [...partial.content, { type: "thinking", thinking: "" }]; + stream.push({ type: "thinking_start", contentIndex: index, partial: { ...partial } }); + for (const chunk of splitStringByTokenSize(block.thinking, minTokenSize, maxTokenSize)) { + await scheduleChunk(chunk, tokensPerSecond); + if (signal?.aborted) { + const aborted = createAbortedMessage(partial); + stream.push({ type: "error", reason: "aborted", error: aborted }); + stream.end(aborted); + return; + } + partial.content[index].thinking += chunk; + stream.push({ type: "thinking_delta", contentIndex: index, delta: chunk, partial: { ...partial } }); + } + stream.push({ + type: "thinking_end", + contentIndex: index, + content: block.thinking, + partial: { ...partial } + }); + continue; + } + if (block.type === "text") { + partial.content = [...partial.content, { type: "text", text: "" }]; + stream.push({ type: "text_start", contentIndex: index, partial: { ...partial } }); + for (const chunk of splitStringByTokenSize(block.text, minTokenSize, maxTokenSize)) { + await scheduleChunk(chunk, tokensPerSecond); + if (signal?.aborted) { + const aborted = createAbortedMessage(partial); + stream.push({ type: "error", reason: "aborted", error: aborted }); + stream.end(aborted); + return; + } + partial.content[index].text += chunk; + stream.push({ type: "text_delta", contentIndex: index, delta: chunk, partial: { ...partial } }); + } + stream.push({ type: "text_end", contentIndex: index, content: block.text, partial: { ...partial } }); + continue; + } + partial.content = [...partial.content, { type: "toolCall", id: block.id, name: block.name, arguments: {} }]; + stream.push({ type: "toolcall_start", contentIndex: index, partial: { ...partial } }); + const toolArguments = new ToolCallArgumentsStream(); + for (const chunk of splitStringByTokenSize(JSON.stringify(block.arguments), minTokenSize, maxTokenSize)) { + await scheduleChunk(chunk, tokensPerSecond); + if (signal?.aborted) { + const aborted = createAbortedMessage(partial); + stream.push({ type: "error", reason: "aborted", error: aborted }); + stream.end(aborted); + return; + } + partial.content[index].arguments = toolArguments.append(chunk); + stream.push({ type: "toolcall_delta", contentIndex: index, delta: chunk, partial: { ...partial } }); + } + partial.content[index].arguments = block.arguments; + stream.push({ type: "toolcall_end", contentIndex: index, toolCall: block, partial: { ...partial } }); + } + if (message.stopReason === "pending") { + throw new Error("Faux response ended without a stop reason"); + } + if (message.stopReason === "error" || message.stopReason === "aborted") { + stream.push({ type: "error", reason: message.stopReason, error: message }); + stream.end(message); + return; + } + stream.push({ type: "done", reason: message.stopReason, message }); + stream.end(message); +} +function createFauxCore(options) { + const api = options.api ?? randomId(DEFAULT_API); + const provider2 = options.provider ?? DEFAULT_PROVIDER; + const minTokenSize = Math.max(1, Math.min(options.tokenSize?.min ?? DEFAULT_MIN_TOKEN_SIZE, options.tokenSize?.max ?? DEFAULT_MAX_TOKEN_SIZE)); + const maxTokenSize = Math.max(minTokenSize, options.tokenSize?.max ?? DEFAULT_MAX_TOKEN_SIZE); + let pendingResponses = []; + const tokensPerSecond = options.tokensPerSecond; + const state = { callCount: 0, deferredFetchCount: 0, cancelledDeferred: [] }; + const promptCache = /* @__PURE__ */ new Map(); + const deferredResponses = /* @__PURE__ */ new Map(); + const modelDefinitions = options.models?.length ? options.models : [ + { + id: DEFAULT_MODEL_ID, + name: DEFAULT_MODEL_NAME, + reasoning: false, + input: ["text", "image"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 128e3, + maxTokens: 16384 + } + ]; + const models2 = modelDefinitions.map((definition) => ({ + id: definition.id, + name: definition.name ?? definition.id, + api, + provider: provider2, + baseUrl: DEFAULT_BASE_URL, + reasoning: definition.reasoning ?? false, + input: definition.input ?? ["text", "image"], + inputLimits: definition.inputLimits, + cost: definition.cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: definition.contextWindow ?? 128e3, + maxTokens: definition.maxTokens ?? 16384 + })); + const resolveResponse = async (step, context, streamOptions, requestModel) => { + const resolved = typeof step === "function" ? await step(context, streamOptions, state, requestModel) : step; + return withUsageEstimate(cloneMessage(resolved, api, provider2, requestModel.id), context, streamOptions, promptCache); + }; + const stream = (requestModel, context, streamOptions) => { + const outer = createAssistantMessageEventStream(); + const step = pendingResponses.shift(); + state.callCount++; + queueMicrotask(async () => { + try { + await streamOptions?.onResponse?.({ status: 200, headers: {} }, requestModel); + if (!step) { + let message2 = createErrorMessage(new Error("No more faux responses queued"), api, provider2, requestModel.id); + message2 = withUsageEstimate(message2, context, streamOptions, promptCache); + outer.push({ type: "error", reason: "error", error: message2 }); + outer.end(message2); + return; + } + if (streamOptions?.deferred) { + const handle = { + provider: requestModel.provider, + modelId: requestModel.id, + api: requestModel.api, + id: randomId("deferred"), + ...options.deferred?.pollAfterMs !== void 0 ? { pollAfterMs: options.deferred.pollAfterMs } : {} + }; + deferredResponses.set(handle.id, { + handle, + step, + context, + options: streamOptions, + model: requestModel, + pendingFetches: Math.max(0, Math.floor(options.deferred?.pendingFetches ?? 0)), + cancelled: false + }); + await streamWithDeltas(outer, createDeferredMessage(requestModel, handle), minTokenSize, maxTokenSize, tokensPerSecond, streamOptions.signal); + return; + } + const message = await resolveResponse(step, context, streamOptions, requestModel); + await streamWithDeltas(outer, message, minTokenSize, maxTokenSize, tokensPerSecond, streamOptions?.signal); + } catch (error) { + const message = createErrorMessage(error, api, provider2, requestModel.id); + outer.push({ type: "error", reason: "error", error: message }); + outer.end(message); + } + }); + return outer; + }; + const streamSimple = (streamModel, context, streamOptions) => stream(streamModel, context, streamOptions); + const fetchDeferred = (requestModel, handle, fetchOptions) => { + const outer = createAssistantMessageEventStream(); + state.deferredFetchCount++; + queueMicrotask(async () => { + try { + await fetchOptions?.onResponse?.({ status: 200, headers: {} }, requestModel); + const entry2 = deferredResponses.get(handle.id); + if (!entry2 || entry2.handle.provider !== handle.provider || entry2.handle.modelId !== handle.modelId || entry2.handle.api !== handle.api) { + throw new Error(`Unknown faux deferred response: ${handle.id}`); + } + if (entry2.cancelled) + throw new Error(`Faux deferred response was cancelled: ${handle.id}`); + if (entry2.pendingFetches > 0) { + entry2.pendingFetches--; + await streamWithDeltas(outer, createDeferredMessage(requestModel, entry2.handle), minTokenSize, maxTokenSize, tokensPerSecond, fetchOptions?.signal); + return; + } + if (!entry2.final) { + const { deferred: _deferred, signal: _submissionSignal, onResponse: _submissionOnResponse, ...submissionOptions } = entry2.options ?? {}; + try { + entry2.final = await resolveResponse(entry2.step, entry2.context, submissionOptions, entry2.model); + } catch (error) { + entry2.final = createErrorMessage(error, api, provider2, entry2.model.id); + } + } + await streamWithDeltas(outer, entry2.final, minTokenSize, maxTokenSize, tokensPerSecond, fetchOptions?.signal); + } catch (error) { + const message = createErrorMessage(error, api, provider2, requestModel.id); + outer.push({ type: "error", reason: "error", error: message }); + outer.end(message); + } + }); + return outer; + }; + const cancelDeferred2 = async (requestModel, handle, cancelOptions) => { + state.cancelledDeferred.push(structuredClone(handle)); + const entry2 = deferredResponses.get(handle.id); + if (entry2) + entry2.cancelled = true; + await cancelOptions?.onResponse?.({ status: 200, headers: {} }, requestModel); + }; + function getModel(requestedModelId) { + if (!requestedModelId) { + return models2[0]; + } + return models2.find((candidate) => candidate.id === requestedModelId); + } + return { + api, + provider: provider2, + models: models2, + stream, + streamSimple, + fetchDeferred, + cancelDeferred: cancelDeferred2, + getModel, + state, + setResponses(responses) { + pendingResponses = [...responses]; + }, + appendResponses(responses) { + pendingResponses.push(...responses); + }, + getPendingResponseCount() { + return pendingResponses.length; + } + }; +} +function fauxProvider(options = {}) { + const core = createFauxCore(options); + const provider2 = createProvider({ + id: core.provider, + auth: { apiKey: { name: "Faux", resolve: async () => ({ auth: {} }) } }, + models: core.models, + api: { + stream: core.stream, + streamSimple: core.streamSimple, + fetchDeferred: core.fetchDeferred, + cancelDeferred: core.cancelDeferred + } + }); + return { + provider: provider2, + api: core.api, + models: core.models, + getModel: core.getModel, + state: core.state, + setResponses: core.setResponses, + appendResponses: core.appendResponses, + getPendingResponseCount: core.getPendingResponseCount + }; +} + +// node_modules/@earendil-works/pi-schema/dist/resolver.js +var DEFAULT_BASE = "https://json-schema.invalid/root.json"; +var Resolver = class { + draft; + rootBase; + /** Schema object to the base URI it was indexed under. */ + baseOf = /* @__PURE__ */ new Map(); + /** URI (with a `#name` fragment) of every `$dynamicAnchor`, to its schema. */ + dynamicAnchors = /* @__PURE__ */ new Map(); + root; + options; + registry = /* @__PURE__ */ new Map(); + rejectUnresolved; + /** The references that named nothing and resolved to `false` (with `unresolvedRefs: "reject"`). */ + unresolved = /* @__PURE__ */ new Set(); + resources = /* @__PURE__ */ new Map(); + anchors = /* @__PURE__ */ new Map(); + indexed = false; + constructor(root2, options) { + this.draft = options.draft === "7" ? "7" : "2020-12"; + this.root = root2; + this.options = options; + this.rejectUnresolved = options.unresolvedRefs === "reject"; + this.rootBase = isSchemaObject(root2) ? this.baseFor(root2, DEFAULT_BASE) : DEFAULT_BASE; + } + /** + * The base URI of `node`, whose parent has `base`: its `$id` changes it, unless draft 7 makes the `$id` inert. Once + * the schema is indexed, the indexed base (a resolved reference target already has its own). + */ + baseFor(node, base) { + const indexed = this.baseOf.get(node); + if (indexed !== void 0) + return indexed; + const id = node.$id; + if (typeof id !== "string") + return base; + if (this.draft === "7" && (typeof node.$ref === "string" || id.startsWith("#"))) + return base; + return documentOf(resolveUri(id, base)); + } + /** Indexes the root schema and the registered documents' URIs (once). */ + ensureIndexed() { + if (this.indexed) + return; + this.indexed = true; + for (const [uri, schema] of Object.entries(this.options.schemas ?? {})) { + this.registry.set(documentOf(resolveUri(uri, DEFAULT_BASE)), schema); + } + this.resources.set(DEFAULT_BASE, this.root); + this.index(this.root, DEFAULT_BASE); + } + /** + * The schema a reference names, with the base URI it compiles under. Throws if it names nothing, or, with + * `unresolvedRefs: "reject"`, resolves to `false`, the schema no value passes. + */ + resolve(ref, base) { + this.ensureIndexed(); + if (!this.rejectUnresolved) + return this.find(ref, base); + try { + return this.find(ref, base); + } catch { + this.unresolved.add(resolveUri(ref, base)); + return { node: false, base }; + } + } + /** Whether `ref`, from `base`, named nothing and resolved to `false`. */ + isUnresolved(ref, base) { + return this.unresolved.has(resolveUri(ref, base)); + } + find(ref, base) { + const uri = resolveUri(ref, base); + const doc = documentOf(uri); + const fragment = uri.length > doc.length ? decodeURIComponent(uri.slice(doc.length + 1)) : ""; + const root2 = this.resources.has(doc) ? this.resources.get(doc) : this.load(doc); + if (root2 === void 0) + throw new Error(`Unresolved $ref ${ref} (no schema registered for ${doc})`); + if (fragment === "") + return { node: root2, base: doc }; + if (fragment.startsWith("/")) + return this.pointer(root2, doc, fragment); + const target = this.anchors.get(`${doc}#${fragment}`); + if (target === void 0) + throw new Error(`Unresolved $ref ${ref} (no anchor ${fragment} in ${doc})`); + return { node: target, base: this.baseOf.get(target) ?? doc }; + } + /** Whether `node` is the root of the schema resource at `base`. */ + isResource(node, base) { + this.ensureIndexed(); + return this.resources.get(base) === node; + } + // Walks only keywords that hold subschemas: an `$id` inside `enum`, `const` or an unknown keyword names nothing. + index(node, base) { + if (!isSchemaObject(node) || this.baseOf.has(node)) + return; + let b = base; + const refOnly = this.draft === "7" && typeof node.$ref === "string"; + if (!refOnly && typeof node.$id === "string") { + if (this.draft === "7" && node.$id.startsWith("#")) + this.anchors.set(documentOf(b) + node.$id, node); + else { + const uri = resolveUri(node.$id, b); + b = documentOf(uri); + this.resources.set(b, node); + if (uri.length > b.length + 1) + this.anchors.set(uri, node); + } + } + this.baseOf.set(node, b); + if (refOnly) + return; + if (this.draft !== "7") { + if (typeof node.$anchor === "string") + this.anchors.set(`${b}#${node.$anchor}`, node); + if (typeof node.$dynamicAnchor === "string") { + this.anchors.set(`${b}#${node.$dynamicAnchor}`, node); + this.dynamicAnchors.set(`${b}#${node.$dynamicAnchor}`, node); + } + } + for (const key of SCHEMA_KEYWORDS) + this.index(node[key], b); + for (const key of MAP_KEYWORDS) { + const map = node[key]; + if (isSchemaObject(map)) + for (const k of Object.keys(map)) + this.index(map[k], b); + } + for (const key of ARRAY_KEYWORDS) { + const list = node[key]; + if (Array.isArray(list)) + for (const s of list) + this.index(s, b); + } + } + load(doc) { + const schema = this.registry.get(doc); + if (schema === void 0) + return void 0; + this.resources.set(doc, schema); + this.index(schema, doc); + return schema; + } + pointer(root2, base, fragment) { + let node = root2; + let b = base; + for (const raw of fragment.split("/").slice(1)) { + const key = raw.replace(/~1/g, "/").replace(/~0/g, "~"); + node = typeof node === "object" && node !== null && Object.hasOwn(node, key) ? node[key] : void 0; + if (node === void 0) + throw new Error(`Unresolved $ref #${fragment} in ${base}`); + if (typeof node === "object" && node !== null) + b = this.baseOf.get(node) ?? b; + } + return { node, base: b }; + } +}; +var SCHEMA_KEYWORDS = [ + "additionalProperties", + "propertyNames", + "contains", + "not", + "if", + "then", + "else", + "unevaluatedProperties", + "unevaluatedItems", + "additionalItems", + "contentSchema", + "items" +]; +var MAP_KEYWORDS = ["properties", "patternProperties", "$defs", "definitions", "dependentSchemas", "dependencies"]; +var ARRAY_KEYWORDS = ["allOf", "anyOf", "oneOf", "prefixItems", "items"]; +function isSchemaObject(value2) { + return typeof value2 === "object" && value2 !== null && !Array.isArray(value2); +} +function resolveUri(ref, base) { + try { + return new URL(ref, base).href; + } catch { + return ref.startsWith("#") ? documentOf(base) + ref : ref; + } +} +function documentOf(uri) { + const hash = uri.indexOf("#"); + return hash < 0 ? uri : uri.slice(0, hash); +} + +// node_modules/@earendil-works/pi-schema/dist/shared.js +function sharedRegex(source) { + const hit = regexes.get(source)?.deref(); + if (hit !== void 0) + return hit; + let re; + try { + re = new RegExp(source, "u"); + } catch { + re = new RegExp(source); + } + regexes.set(source, new WeakRef(re)); + regexCleanup.register(re, source); + return re; +} +var regexes = /* @__PURE__ */ new Map(); +var regexCleanup = new FinalizationRegistry((source) => { + if (regexes.get(source)?.deref() === void 0) + regexes.delete(source); +}); + +// node_modules/@earendil-works/pi-schema/dist/coerce.js +var Coercer = class { + c; + schema; + /** + * The (schema node, value) pairs pass 2 is converting through a re-entry point, as a stack. Conversion can enter + * a node again with the same value only through a `$ref` or by wrapping a single value into an array (also for + * schemas that cycle through shared JS objects): a recursive schema that meets a value no branch accepts would + * convert it without end. A pair already on the stack (primitives by value, objects by reference) leaves the value + * unchanged. Only those two points push, so schemas without references or wraps pay nothing. + */ + entered = []; + /** How often a re-entry was cut short in this coerce() call; results computed across one are not memoized. */ + cuts = 0; + /** + * Results of `$ref` targets by (node, value) within one coerce() call: a recursive union whose branches all + * convert the same children (and all fail) would convert them once per branch, exponentially in the depth. + */ + memo = void 0; + constructor(compiler2, schema) { + this.c = compiler2; + this.schema = schema; + } + /** `value` coerced: a copy along the changed paths only, or `value` itself when nothing changes. */ + coerce(value2) { + const base = this.c.r.rootBase; + const withoutNulls = this.dropOptionalNulls(value2, this.schema, base); + return this.coerceTypes(this.convertOnly(withoutNulls), this.schema, base); + } + /** Pass 2 alone, as TypeBox's `Value.Convert` (the TypeBox conformance tests run it). */ + convertOnly(value2) { + try { + return this.convert(this.schema, this.c.r.rootBase, value2); + } finally { + this.memo = void 0; + this.cuts = 0; + } + } + /** `node` converted for `value` at a re-entry point: unchanged when that pair is already being converted. */ + reenter(node, base, value2, memoize) { + const entered = this.entered; + for (let i = 0; i < entered.length; i += 2) { + if (entered[i] === node && Object.is(entered[i + 1], value2)) { + this.cuts++; + return value2; + } + } + const memo = memoize ? this.memo?.get(node) : void 0; + if (memo?.has(value2)) + return memo.get(value2); + const cuts = this.cuts; + entered.push(node, value2); + let result; + try { + result = this.convert(node, base, value2); + } finally { + entered.length -= 2; + } + if (memoize && this.cuts === cuts) { + this.memo ??= /* @__PURE__ */ new Map(); + let values = this.memo.get(node); + if (values === void 0) { + values = /* @__PURE__ */ new Map(); + this.memo.set(node, values); + } + values.set(value2, result); + } + return result; + } + /** Whether `value` passes the schema `node`; undefined when `node` cannot be compiled. */ + passes(node, base, value2) { + try { + return this.c.check(node, this.baseOf(node, base))(value2); + } catch { + return void 0; + } + } + baseOf(node, base) { + return isSchemaObject(node) ? this.c.r.baseOf.get(node) ?? base : base; + } + // --------------------------------------------------------------------------------------------------------------- + // Pass 1: optional nulls + // --------------------------------------------------------------------------------------------------------------- + dropOptionalNulls(value2, schema, base) { + if (!isSchemaObject(schema)) + return value2; + const b = this.baseOf(schema, base); + if (Array.isArray(value2)) { + return mapItems(value2, (item, i) => { + const itemSchema = itemSchemaAt(schema, i); + return itemSchema === void 0 ? item : this.dropOptionalNulls(item, itemSchema, b); + }); + } + if (!isPlainObject(value2)) + return value2; + const properties = isSchemaObject(schema.properties) ? schema.properties : {}; + const patterns = isSchemaObject(schema.patternProperties) ? Object.entries(schema.patternProperties).map(([pattern, item]) => [sharedRegex(pattern), item]) : []; + const additional = isSchemaObject(schema.additionalProperties) ? schema.additionalProperties : void 0; + if (patterns.length === 0 && additional === void 0 && !isSchemaObject(schema.properties)) + return value2; + const required = new Set(Array.isArray(schema.required) ? schema.required : []); + let out; + const set = (key, next) => { + if (next === (out ?? value2)[key]) + return; + out ??= { ...value2 }; + out[key] = next; + }; + for (const [key, property] of Object.entries(properties)) { + if (!Object.hasOwn(value2, key)) + continue; + const isRef = isSchemaObject(property) && typeof property.$ref === "string"; + if (value2[key] === null && !required.has(key) && !isRef && this.passes(property, b, null) === false) { + out ??= { ...value2 }; + delete out[key]; + continue; + } + set(key, this.dropOptionalNulls(value2[key], property, b)); + } + if (patterns.length > 0 || additional !== void 0) { + for (const key of Object.keys(value2)) { + let matched = Object.hasOwn(properties, key); + for (const [pattern, item] of patterns) { + if (!pattern.test(key)) + continue; + matched = true; + set(key, this.dropOptionalNulls((out ?? value2)[key], item, b)); + } + if (!matched && additional !== void 0) + set(key, this.dropOptionalNulls(value2[key], additional, b)); + } + } + return out ?? value2; + } + // --------------------------------------------------------------------------------------------------------------- + // Pass 2: TypeBox's conversion rules + // --------------------------------------------------------------------------------------------------------------- + convert(node, base, value2) { + if (!isSchemaObject(node)) + return value2; + const b = this.baseOf(node, base); + if (typeof node.$ref === "string") { + let target; + try { + target = this.c.r.resolve(node.$ref, b); + } catch { + return value2; + } + return isSchemaObject(target.node) ? this.reenter(target.node, target.base, value2, true) : value2; + } + return this.convertNode(node, b, value2); + } + /** One schema node's conversion: its first keyword among `const`, `enum`, the unions, `allOf` and `type`. */ + convertNode(node, b, value2) { + if (Object.hasOwn(node, "const")) + return convertLiteral(node.const, value2); + if (Array.isArray(node.enum)) + return this.convertEnum(node, node.enum, b, value2); + if (Array.isArray(node.anyOf)) + return this.convertUnion(node, node.anyOf, b, value2); + if (Array.isArray(node.oneOf)) + return this.convertUnion(node, node.oneOf, b, value2); + if (Array.isArray(node.allOf)) { + let next = value2; + for (const member of node.allOf) + next = this.convert(member, b, next); + return this.convertMembers(node, b, next); + } + switch (node.type) { + case "string": + return orValue(tryString(value2), value2); + case "number": + return orValue(tryNumber(value2), value2); + case "integer": { + const result = tryNumber(value2); + return result === void 0 ? value2 : Math.trunc(result.value); + } + case "boolean": + return orValue(tryBoolean(value2), value2); + case "null": + return orValue(tryNull(value2), value2); + case "array": + return this.convertArray(node, b, value2); + case "object": + return this.convertObject(node, b, value2); + case void 0: + if (node.properties !== void 0 || node.patternProperties !== void 0) { + return this.convertObject(node, b, value2); + } + if (node.items !== void 0 || node.prefixItems !== void 0) + return this.convertArray(node, b, value2); + return value2; + default: + return value2; + } + } + /** An enum is a union of its values: a member stays, else the first value the input converts to. */ + convertEnum(node, values, base, value2) { + if (values.some((member) => member === value2)) + return value2; + for (const member of values) { + const candidate = convertLiteral(member, value2); + if (candidate !== value2 && this.passes(node, base, candidate) === true) + return candidate; + } + return value2; + } + /** + * A value one branch accepts stays; else the first branch's conversion that the whole union accepts. Branches are + * converted in order and only until one is accepted, so a later recursive branch is not entered needlessly. A node + * that also declares members (plain JSON Schema; TypeBox's never do) converts them into each candidate before it is + * checked, so a branch is not discarded for a sibling property that is converted after it. + */ + convertUnion(node, branches, base, value2) { + if (branches.some((branch) => this.passes(branch, base, value2) === true)) + return this.convertMembers(node, base, value2); + for (const branch of branches) { + const candidate = this.convertMembers(node, base, this.convert(branch, base, value2)); + if (this.passes(node, base, candidate) === true) + return candidate; + } + return this.convertMembers(node, base, value2); + } + /** The object members of a union or intersection node, when it declares any. */ + convertMembers(node, base, value2) { + const declares = node.properties !== void 0 || node.patternProperties !== void 0 || node.additionalProperties !== void 0; + return declares ? this.convertObject(node, base, value2) : value2; + } + convertArray(node, base, value2) { + const prefix = Array.isArray(node.items) ? node.items : Array.isArray(node.prefixItems) ? node.prefixItems : void 0; + if (prefix !== void 0) { + if (!Array.isArray(value2)) + return value2; + const rest = Array.isArray(node.items) ? void 0 : node.items; + return mapItems(value2, (item2, i) => { + const schema = i < prefix.length ? prefix[i] : rest; + return schema === void 0 ? item2 : this.convert(schema, base, item2); + }); + } + if (Array.isArray(value2)) { + return node.items === void 0 ? value2 : mapItems(value2, (item2) => this.convert(node.items, base, item2)); + } + const item = node.items; + return [isSchemaObject(item) ? this.reenter(item, base, value2, false) : value2]; + } + convertObject(node, base, value2) { + if (!isPlainObject(value2)) + return value2; + const properties = isSchemaObject(node.properties) ? node.properties : {}; + const patterns = isSchemaObject(node.patternProperties) ? Object.entries(node.patternProperties).map(([pattern, schema]) => [sharedRegex(pattern), schema]) : []; + const additional = isSchemaObject(node.additionalProperties) ? node.additionalProperties : void 0; + let out; + for (const key of Object.keys(value2)) { + if (value2[key] === void 0) + continue; + let next = value2[key]; + let matched = Object.hasOwn(properties, key); + if (matched) + next = this.convert(properties[key], base, next); + for (const [pattern, schema] of patterns) { + if (!pattern.test(key)) + continue; + matched = true; + next = this.convert(schema, base, next); + } + if (!matched && additional !== void 0) + next = this.convert(additional, base, next); + if (next !== value2[key]) { + out ??= { ...value2 }; + out[key] = next; + } + } + return out ?? value2; + } + // --------------------------------------------------------------------------------------------------------------- + // Pass 3: primitive coercion by type + // --------------------------------------------------------------------------------------------------------------- + coerceTypes(value2, schema, base) { + if (!isSchemaObject(schema)) + return value2; + const b = this.baseOf(schema, base); + let next = value2; + if (Array.isArray(schema.allOf)) + for (const member of schema.allOf) + next = this.coerceTypes(next, member, b); + if (Array.isArray(schema.anyOf)) + next = this.coerceUnion(next, schema.anyOf, b); + if (Array.isArray(schema.oneOf)) + next = this.coerceUnion(next, schema.oneOf, b); + const types = typesOf(schema); + const matchesUnionMember = types.length > 1 && types.some((type) => matchesType(next, type)); + if (types.length > 0 && !matchesUnionMember) { + for (const type of types) { + const candidate = coercePrimitive(next, type); + if (candidate !== next) { + next = candidate; + break; + } + } + } + if (types.includes("object") && isPlainObject(next)) + next = this.coerceProperties(next, schema, b); + if (types.includes("array") && Array.isArray(next)) + next = this.coerceItems(next, schema, b); + return next; + } + coerceUnion(value2, branches, base) { + for (const branch of branches) + if (this.passes(branch, base, value2) === true) + return value2; + for (const branch of branches) { + const coerced = this.coerceTypes(value2, branch, base); + if (this.passes(branch, base, coerced) === true) + return coerced; + } + return value2; + } + coerceProperties(value2, schema, base) { + const properties = isSchemaObject(schema.properties) ? schema.properties : {}; + const patterns = isSchemaObject(schema.patternProperties) ? Object.entries(schema.patternProperties).map(([pattern, item]) => [sharedRegex(pattern), item]) : []; + const additional = isSchemaObject(schema.additionalProperties) ? schema.additionalProperties : void 0; + let out; + const set = (key, next) => { + if (next === (out ?? value2)[key]) + return; + out ??= { ...value2 }; + out[key] = next; + }; + for (const [key, property] of Object.entries(properties)) { + if (key in value2) + set(key, this.coerceTypes(value2[key], property, base)); + } + for (const key of Object.keys(value2)) { + let matched = Object.hasOwn(properties, key); + for (const [pattern, item] of patterns) { + if (!pattern.test(key)) + continue; + matched = true; + set(key, this.coerceTypes((out ?? value2)[key], item, base)); + } + if (!matched && additional !== void 0) + set(key, this.coerceTypes(value2[key], additional, base)); + } + return out ?? value2; + } + coerceItems(value2, schema, base) { + return mapItems(value2, (item, i) => { + const itemSchema = itemSchemaAt(schema, i); + return isSchemaObject(itemSchema) ? this.coerceTypes(item, itemSchema, base) : item; + }); + } +}; +function itemSchemaAt(schema, index) { + if (Array.isArray(schema.items)) + return schema.items[index]; + if (Array.isArray(schema.prefixItems) && index < schema.prefixItems.length) + return schema.prefixItems[index]; + return schema.items; +} +function mapItems(items, map) { + let out; + for (let i = 0; i < items.length; i++) { + const next = map(items[i], i); + if (next === items[i]) + continue; + out ??= items.slice(); + out[i] = next; + } + return out ?? items; +} +function orValue(result, value2) { + return result === void 0 ? value2 : result.value; +} +function convertLiteral(literal, value2) { + if (literal === value2) + return value2; + const result = typeof literal === "string" ? tryString(value2) : typeof literal === "number" ? tryNumber(value2) : typeof literal === "boolean" ? tryBoolean(value2) : void 0; + return result !== void 0 && result.value === literal ? result.value : value2; +} +function tryString(value2) { + if (typeof value2 === "bigint" || typeof value2 === "boolean" || isFiniteNumber(value2)) + return { value: String(value2) }; + if (value2 === null) + return { value: "null" }; + if (typeof value2 === "string") + return { value: value2 }; + if (value2 === void 0) + return { value: "" }; + return void 0; +} +var MAX_BIGINT = BigInt(Number.MAX_SAFE_INTEGER); +var MIN_BIGINT = BigInt(Number.MIN_SAFE_INTEGER); +function tryNumber(value2) { + if (typeof value2 === "bigint") + return value2 <= MAX_BIGINT && value2 >= MIN_BIGINT ? { value: Number(value2) } : void 0; + if (typeof value2 === "boolean") + return { value: value2 ? 1 : 0 }; + if (isFiniteNumber(value2)) + return { value: value2 }; + if (value2 === null || value2 === void 0) + return { value: 0 }; + if (typeof value2 !== "string") + return void 0; + const coerced = +value2; + if (Number.isFinite(coerced)) + return { value: coerced }; + const lowercase = value2.toLowerCase(); + if (lowercase === "false") + return { value: 0 }; + if (lowercase === "true") + return { value: 1 }; + const big = bigIntOfString(value2); + return big !== void 0 && big <= MAX_BIGINT && big >= MIN_BIGINT ? { value: Number(big) } : void 0; +} +function bigIntOfString(value2) { + if (/^-?(0|[1-9]\d*)n$/.test(value2)) + return BigInt(value2.slice(0, -1)); + if (/^-?(0|[1-9]\d*)\.\d+$/.test(value2)) + return BigInt(value2.split(".")[0]); + if (/^-?(0|[1-9]\d*)$/.test(value2)) + return BigInt(value2); + return void 0; +} +function tryBoolean(value2) { + if (typeof value2 === "bigint") + return value2 === 0n ? { value: false } : value2 === 1n ? { value: true } : void 0; + if (typeof value2 === "boolean") + return { value: value2 }; + if (isFiniteNumber(value2)) + return value2 === 0 ? { value: false } : value2 === 1 ? { value: true } : void 0; + if (value2 === null || value2 === void 0) + return { value: false }; + if (typeof value2 !== "string") + return void 0; + const lowercase = value2.toLowerCase(); + if (lowercase === "false" || value2 === "0") + return { value: false }; + if (lowercase === "true" || value2 === "1") + return { value: true }; + return void 0; +} +function tryNull(value2) { + if (typeof value2 === "bigint") + return value2 === 0n ? { value: null } : void 0; + if (typeof value2 === "boolean") + return value2 === false ? { value: null } : void 0; + if (isFiniteNumber(value2)) + return value2 === 0 ? { value: null } : void 0; + if (value2 === null || value2 === void 0) + return { value: null }; + if (typeof value2 !== "string") + return void 0; + const lowercase = value2.toLowerCase(); + return lowercase === "undefined" || lowercase === "null" || value2 === "" || value2 === "0" ? { value: null } : void 0; +} +function isFiniteNumber(value2) { + return typeof value2 === "number" && Number.isFinite(value2); +} +function typesOf(schema) { + if (typeof schema.type === "string") + return [schema.type]; + if (Array.isArray(schema.type)) + return schema.type.filter((type) => typeof type === "string"); + return []; +} +function matchesType(value2, type) { + switch (type) { + case "number": + return typeof value2 === "number"; + case "integer": + return typeof value2 === "number" && Number.isInteger(value2); + case "boolean": + return typeof value2 === "boolean"; + case "string": + return typeof value2 === "string"; + case "null": + return value2 === null; + case "array": + return Array.isArray(value2); + case "object": + return isPlainObject(value2); + default: + return false; + } +} +function coercePrimitive(value2, type) { + switch (type) { + case "number": + case "integer": { + if (value2 === null) + return 0; + if (typeof value2 === "string" && value2.trim() !== "") { + const parsed = Number(value2); + if (type === "number" ? Number.isFinite(parsed) : Number.isInteger(parsed)) + return parsed; + } + if (typeof value2 === "boolean") + return value2 ? 1 : 0; + return value2; + } + case "boolean": + if (value2 === null) + return false; + if (value2 === "true" || value2 === 1) + return true; + if (value2 === "false" || value2 === 0) + return false; + return value2; + case "string": + if (value2 === null) + return ""; + if (typeof value2 === "number" || typeof value2 === "boolean") + return String(value2); + return value2; + case "null": + return value2 === "" || value2 === 0 || value2 === false ? null : value2; + default: + return value2; + } +} +function isPlainObject(value2) { + return typeof value2 === "object" && value2 !== null && !Array.isArray(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/checks.js +var ALWAYS = () => true; +var NEVER = () => false; +var IS_STRING = (v) => typeof v === "string"; +var IS_NUMBER = (v) => typeof v === "number"; +var IS_INTEGER = (v) => Number.isInteger(v); +var IS_BOOLEAN = (v) => typeof v === "boolean"; +var IS_NULL = (v) => v === null; +var IS_ARRAY = (v) => Array.isArray(v); +var IS_BYTES = (v) => v instanceof Uint8Array; +var IS_OBJECT = (v) => isObject(v); +function isObject(v) { + return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Uint8Array); +} +var TYPE_CHECKS = /* @__PURE__ */ new Map([ + ["string", IS_STRING], + ["number", IS_NUMBER], + ["integer", IS_INTEGER], + ["boolean", IS_BOOLEAN], + ["null", IS_NULL], + ["array", IS_ARRAY], + ["object", IS_OBJECT], + ["bytes", IS_BYTES] +]); +var LEAF_CODES = /* @__PURE__ */ new Map([ + [IS_STRING, 1], + [IS_NUMBER, 2], + [IS_INTEGER, 3], + [IS_BOOLEAN, 4], + [IS_NULL, 5], + [ALWAYS, 6] +]); +function leafOk(code, x) { + switch (code) { + case 1: + return typeof x === "string"; + case 2: + return typeof x === "number"; + case 3: + return Number.isInteger(x); + case 4: + return typeof x === "boolean"; + case 5: + return x === null; + default: + return true; + } +} +var GUARD_NONE = 0; +var GUARD_STRICT = 1; +var GUARD_LOOSE = 2; +var CODE = 7; +var REQUIRED = 8; +var INHERITED = 16; +function and(parts) { + switch (parts.length) { + case 0: + return ALWAYS; + case 1: + return parts[0]; + case 2: { + const [a, b] = parts; + return (v) => a(v) && b(v); + } + case 3: { + const [a, b, c] = parts; + return (v) => a(v) && b(v) && c(v); + } + default: + return (v) => { + for (let i = 0; i < parts.length; i++) + if (!parts[i](v)) + return false; + return true; + }; + } +} +function indirect(slot) { + return (v) => slot.check(v); +} +function scopedCheck(scope, uri, check) { + return (v) => { + scope.push(uri); + const ok = check(v); + scope.pop(); + return ok; + }; +} +function typeCheck(types) { + const checks = types.map((t) => (typeof t === "string" ? TYPE_CHECKS.get(t) : void 0) ?? NEVER); + if (checks.length === 1) + return checks[0]; + return (v) => { + for (let i = 0; i < checks.length; i++) + if (checks[i](v)) + return true; + return false; + }; +} +function bytesCheck(min, max) { + return (v) => v instanceof Uint8Array && v.length >= min && v.length <= max; +} +function codePoints(s) { + let n = 0; + for (let i = 0; i < s.length; i++, n++) { + const c = s.charCodeAt(i); + if (c >= 55296 && c <= 56319 && i + 1 < s.length) { + const next = s.charCodeAt(i + 1); + if (next >= 56320 && next <= 57343) + i++; + } + } + return n; +} +function lengthOk(s, min, max) { + const units = s.length; + if (units < min) + return false; + if (units < 2 * min && codePoints(s) < min) + return false; + return units <= max || codePoints(s) <= max; +} +function stringCheck(strict, min, max, re, format) { + if (re !== void 0 && min === 0 && max === Number.POSITIVE_INFINITY && format === void 0) { + return strict ? (v) => typeof v === "string" && re.test(v) : (v) => typeof v !== "string" || re.test(v); + } + if (re === void 0 && format === void 0) { + return strict ? (v) => typeof v === "string" && lengthOk(v, min, max) : (v) => typeof v !== "string" || lengthOk(v, min, max); + } + return (v) => { + if (typeof v !== "string") + return !strict; + return lengthOk(v, min, max) && (re === void 0 || re.test(v)) && (format === void 0 || format(v)); + }; +} +function numberCheck(mode, min, max, xmin, xmax, multipleOf) { + return (v) => { + if (typeof v !== "number") + return mode === 0; + if (mode === 2 && !Number.isInteger(v)) + return false; + return v >= min && v <= max && v > xmin && v < xmax && (multipleOf === void 0 || isMultiple(v, multipleOf)); + }; +} +function isMultiple(v, d) { + const q = v / d; + if (Number.isInteger(q)) + return true; + if (!Number.isFinite(q)) + return v % d === 0; + const [vc, ve] = decimal(v); + const [dc, de] = decimal(d); + return ve >= de ? vc * 10n ** BigInt(ve - de) % dc === 0n : vc % (dc * 10n ** BigInt(de - ve)) === 0n; +} +function decimal(x) { + const [mantissa, exponent = "0"] = Math.abs(x).toString().split("e"); + const point = mantissa.indexOf("."); + const fraction = point < 0 ? 0 : mantissa.length - point - 1; + return [BigInt(mantissa.replace(".", "")), Number(exponent) - fraction]; +} +function guardObject(inner, strict) { + return strict ? (v) => isObject(v) && inner(v) : (v) => !isObject(v) || inner(v); +} +function guardArray(inner, strict) { + return strict ? (v) => Array.isArray(v) && inner(v) : (v) => !Array.isArray(v) || inner(v); +} +function declaredObject(entries2, requiredCount, closed, guard) { + const n = entries2.length; + return (v) => { + if (guard !== GUARD_NONE && !isObject(v)) + return guard === GUARD_LOOSE; + const o = v; + let required = 0; + for (const k in o) { + let i = 0; + while (i < n && entries2[i] !== k) + i += 3; + if (i === n) { + if (closed) + return false; + continue; + } + const x = o[k]; + if (x === void 0) + continue; + const f = entries2[i + 2]; + const c = f & CODE; + if (c !== 0 ? !leafOk(c, x) : !entries2[i + 1](x)) + return false; + if (f & REQUIRED) + required++; + } + return required === requiredCount; + }; +} +function openObject(entries2, keys, extraRequired, patterns, additional, guard) { + const known = patterns.length > 0 || additional !== void 0 ? new Set(keys) : void 0; + return (v) => { + if (guard !== GUARD_NONE && !isObject(v)) + return guard === GUARD_LOOSE; + const o = v; + for (let i = 0; i < entries2.length; i += 3) { + const k = entries2[i]; + const x = o[k]; + const f = entries2[i + 2]; + if (x === void 0 || f & INHERITED && !Object.hasOwn(o, k)) { + if (f & REQUIRED) + return false; + continue; + } + const c = f & CODE; + if (c !== 0 ? !leafOk(c, x) : !entries2[i + 1](x)) + return false; + } + for (let i = 0; i < extraRequired.length; i++) + if (!Object.hasOwn(o, extraRequired[i])) + return false; + if (known === void 0) + return true; + for (const k of Object.keys(o)) { + let matched = known.has(k); + for (let i = 0; i < patterns.length; i++) { + if (patterns[i][0].test(k)) { + matched = true; + if (!patterns[i][1](o[k])) + return false; + } + } + if (!matched && additional !== void 0 && !additional(o[k])) + return false; + } + return true; + }; +} +function propertyNamesCheck(check) { + return (v) => { + for (const k in v) + if (!check(k)) + return false; + return true; + }; +} +function propertyCountCheck(min, max) { + return (v) => { + let n = 0; + for (const _ in v) + n++; + return n >= min && n <= max; + }; +} +function dependentRequiredCheck(entries2) { + return (v) => { + const o = v; + for (const [k, list] of entries2) + if (Object.hasOwn(o, k)) { + for (const r of list) + if (!Object.hasOwn(o, r)) + return false; + } + return true; + }; +} +function dependentSchemasCheck(entries2) { + return (v) => { + for (const [k, check] of entries2) + if (Object.hasOwn(v, k) && !check(v)) + return false; + return true; + }; +} +function listCheck(guard, min, max, prefix, rest) { + const n = prefix.length; + const code = rest === void 0 ? 0 : LEAF_CODES.get(rest) ?? 0; + return (v) => { + if (!Array.isArray(v)) + return guard === GUARD_LOOSE; + const length = v.length; + if (length < min || length > max) + return false; + const m = length < n ? length : n; + for (let i = 0; i < m; i++) + if (!prefix[i](v[i])) + return false; + if (rest === void 0) + return true; + if (code !== 0) { + for (let i = n; i < length; i++) + if (!leafOk(code, v[i])) + return false; + return true; + } + for (let i = n; i < length; i++) + if (!rest(v[i])) + return false; + return true; + }; +} +function itemsCheck(prefix, rest) { + return listCheck(GUARD_NONE, 0, Number.POSITIVE_INFINITY, prefix, rest); +} +function lengthCheck(min, max) { + return (v) => v.length >= min && v.length <= max; +} +function containsCheck(check, min, max) { + return (v) => { + const list = v; + let n = 0; + for (let i = 0; i < list.length; i++) + if (check(list[i]) && ++n > max) + return false; + return n >= min; + }; +} +function uniqueCheck(v) { + const list = v; + for (let i = 1; i < list.length; i++) + for (let j = 0; j < i; j++) + if (deepEqual(list[i], list[j])) + return false; + return true; +} +function enumCheck(values) { + const primitives = values.filter((x) => typeof x !== "object" || x === null); + if (primitives.length === values.length && primitives.length <= 8) { + return (v) => { + for (let i = 0; i < primitives.length; i++) + if (primitives[i] === v) + return true; + return false; + }; + } + const set = new Set(primitives); + const objects = values.filter((x) => typeof x === "object" && x !== null); + return (v) => set.has(v) || typeof v === "object" && objects.some((o) => deepEqual(v, o)); +} +function constCheck(value2) { + if (typeof value2 !== "object" || value2 === null) + return (v) => v === value2; + return (v) => deepEqual(v, value2); +} +function anyCheck(checks) { + return (v) => { + for (let i = 0; i < checks.length; i++) + if (checks[i](v)) + return true; + return false; + }; +} +function oneCheck(checks) { + return (v) => { + let n = 0; + for (let i = 0; i < checks.length; i++) + if (checks[i](v) && ++n > 1) + return false; + return n === 1; + }; +} +function notCheck(check) { + return (v) => !check(v); +} +function ifCheck(cond, then, otherwise) { + return (v) => cond(v) ? then(v) : otherwise(v); +} +function taggedCheck(key, tags, checks) { + return (v) => { + if (!isObject(v)) + return false; + const tag = v[key]; + for (let i = 0; i < tags.length; i++) + if (tags[i] === tag) + return checks[i](v); + return false; + }; +} +function deepEqual(a, b) { + if (a === b) + return true; + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) + return false; + const array = Array.isArray(a); + if (array !== Array.isArray(b)) + return false; + if (array) { + const x2 = a; + const y2 = b; + if (x2.length !== y2.length) + return false; + for (let i = 0; i < x2.length; i++) + if (!deepEqual(x2[i], y2[i])) + return false; + return true; + } + const x = a; + const y = b; + const keys = Object.keys(x); + if (keys.length !== Object.keys(y).length) + return false; + for (const k of keys) + if (!Object.hasOwn(y, k) || !deepEqual(x[k], y[k])) + return false; + return true; +} + +// node_modules/@earendil-works/pi-schema/dist/annotations.js +function newAnnotations() { + return { props: null, allProps: false, items: 0, allItems: false, indexes: null }; +} +function merge(a, b) { + if (b.props !== null) + for (const k of b.props) + addProp(a, k); + a.allProps ||= b.allProps; + if (b.items > a.items) + a.items = b.items; + a.allItems ||= b.allItems; + if (b.indexes !== null) + for (const i of b.indexes) + addIndex(a, i); +} +function addProp(a, key) { + if (a.props === null) + a.props = /* @__PURE__ */ new Set(); + a.props.add(key); +} +function addIndex(a, index) { + if (a.indexes === null) + a.indexes = /* @__PURE__ */ new Set(); + a.indexes.add(index); +} +var ANNOTATING_TRUE = () => true; +var ANNOTATING_FALSE = () => false; +function indirectAnnotating(slot) { + return (v, a) => slot.check(v, a); +} +function ignoreAnnotations(check) { + return (v) => check(v); +} +function withFreshAnnotations(check) { + return (v) => check(v, newAnnotations()); +} +function scopedAnnotating(scope, uri, check) { + return (v, a) => { + scope.push(uri); + const ok = check(v, a); + scope.pop(); + return ok; + }; +} +function isolateAnnotations(check) { + return (v, a) => { + const b = newAnnotations(); + if (!check(v, b)) + return false; + merge(a, b); + return true; + }; +} +function annotateAll(plain, parts) { + return (v, a) => { + if (!plain(v)) + return false; + for (let i = 0; i < parts.length; i++) + if (!parts[i](v, a)) + return false; + return true; + }; +} +function annotateObject(props, patterns, additional) { + const declared = new Set(props.map(([k]) => k)); + return (v, a) => { + if (!isObject(v)) + return true; + const seen = []; + for (const [k, check] of props) { + if (!Object.hasOwn(v, k)) + continue; + if (!check(v[k])) + return false; + seen.push(k); + } + for (const k of Object.keys(v)) { + let matched = declared.has(k); + for (const [re, check] of patterns) { + if (re.test(k)) { + if (!check(v[k])) + return false; + matched = true; + seen.push(k); + } + } + if (!matched && additional !== void 0) { + if (!additional(v[k])) + return false; + seen.push(k); + } + } + for (const k of seen) + addProp(a, k); + return true; + }; +} +function annotateArray(prefix, rest, contains, minContains, maxContains) { + return (v, a) => { + if (!Array.isArray(v)) + return true; + const m = Math.min(v.length, prefix.length); + for (let i = 0; i < m; i++) + if (!prefix[i](v[i])) + return false; + if (rest !== void 0) { + for (let i = prefix.length; i < v.length; i++) + if (!rest(v[i])) + return false; + a.allItems = true; + } + if (m > a.items) + a.items = m; + if (contains !== void 0) { + let n = 0; + for (let i = 0; i < v.length; i++) { + if (contains(v[i])) { + n++; + addIndex(a, i); + } + } + if (n < minContains || n > maxContains) + return false; + } + return true; + }; +} +function annotateAny(branches, exactlyOne) { + return (v, a) => { + let n = 0; + for (const branch of branches) { + const b = newAnnotations(); + if (branch(v, b)) { + n++; + merge(a, b); + } + } + return exactlyOne ? n === 1 : n > 0; + }; +} +function annotateIf(cond, then, otherwise) { + return (v, a) => { + const b = newAnnotations(); + if (cond(v, b)) { + merge(a, b); + return then === void 0 || then(v, a); + } + return otherwise === void 0 || otherwise(v, a); + }; +} +function annotateDependent(key, check) { + return (v, a) => !isObject(v) || !Object.hasOwn(v, key) || check(v, a); +} +function unevaluatedProperties(check) { + return (v, a) => { + if (!isObject(v) || a.allProps) + return true; + for (const k of Object.keys(v)) + if (!(a.props?.has(k) ?? false) && !check(v[k])) + return false; + a.allProps = true; + return true; + }; +} +function unevaluatedItems(check) { + return (v, a) => { + if (!Array.isArray(v) || a.allItems) + return true; + for (let i = a.items; i < v.length; i++) + if (!(a.indexes?.has(i) ?? false) && !check(v[i])) + return false; + a.allItems = true; + return true; + }; +} + +// node_modules/@earendil-works/pi-schema/dist/compiler.js +var RESTART = /* @__PURE__ */ Symbol("restart"); +var Compiler = class { + r; + draft; + formats; + /** Whether checks track the dynamic scope (the schema has a bookended `$dynamicRef`). */ + dynamic; + schema; + scope; + cache = /* @__PURE__ */ new Map(); + annotatingCache = /* @__PURE__ */ new Map(); + constructor(schema, options, dynamic) { + this.schema = schema; + this.r = new Resolver(schema, options); + this.draft = this.r.draft; + this.formats = options.formats; + this.dynamic = dynamic; + this.scope = []; + } + /** The check of the root schema. */ + root() { + return this.check(this.schema, this.r.rootBase); + } + /** The check of a schema (cached by schema object; a recursive reference goes through an indirection). */ + check(node, base) { + if (node === true) + return ALWAYS; + if (node === false) + return NEVER; + if (!isSchemaObject(node)) + throw new Error(`A schema must be an object or a boolean, got ${JSON.stringify(node)}`); + const cached = this.cache.get(node); + if (cached !== void 0) + return cached; + const bare = this.bareType(node); + if (bare !== void 0) + return bare; + const slot = { check: void 0 }; + this.cache.set(node, indirect(slot)); + const check = this.build(node, this.r.baseFor(node, base)); + slot.check = check; + this.cache.set(node, check); + return check; + } + build(node, base) { + if (this.draft === "7" && typeof node.$ref === "string") + return this.ref(node.$ref, base); + if (this.draft !== "7" && (node.unevaluatedProperties !== void 0 || node.unevaluatedItems !== void 0)) { + return withFreshAnnotations(this.annotating(node, base)); + } + const check = this.plain(node, base); + return this.dynamic && this.r.isResource(node, base) ? scopedCheck(this.scope, base, check) : check; + } + /** + * The module-level check of a schema that is only a `type` (with annotations), `ALWAYS` for one with no assertion + * at all; undefined for every other schema. These are the most common subschemas and cost nothing to share. + */ + bareType(node) { + let type; + for (const k in node) { + if (k === "type") + type = node.type; + else if (!NEUTRAL_KEYWORDS.has(k)) + return void 0; + } + if (type === void 0) + return ALWAYS; + return typeof type === "string" ? TYPE_CHECKS.get(type) : void 0; + } + /** Every keyword of `node`, not tracking annotations. */ + plain(node, base) { + const parts = []; + const types = node.type === void 0 ? void 0 : Array.isArray(node.type) ? node.type : [node.type]; + const single = types?.length === 1 ? types[0] : void 0; + let typeInGroup = false; + if (single === "bytes") { + parts.push(bytesCheck(number(node.minLength) ?? 0, number(node.maxLength) ?? Number.POSITIVE_INFINITY)); + typeInGroup = true; + } else { + const string = this.stringGroup(node, single === "string"); + if (string !== void 0) + parts.push(string); + const numeric = single === "number" || single === "integer"; + const number2 = this.numberGroup(node, single === "number" ? 1 : single === "integer" ? 2 : 0); + if (number2 !== void 0) + parts.push(number2); + const object = this.objectGroup(node, base, single === "object"); + if (object !== void 0) + parts.push(object); + const array = this.arrayGroup(node, base, single === "array"); + if (array !== void 0) + parts.push(array); + typeInGroup = single === "string" && string !== void 0 || numeric && number2 !== void 0 || single === "object" && object !== void 0 || single === "array" && array !== void 0; + } + if (types !== void 0 && !typeInGroup) + parts.unshift(typeCheck(types)); + this.inPlace(node, base, parts); + return and(parts); + } + // The keywords that apply to the value itself, whatever its type. + inPlace(node, base, parts) { + if (Array.isArray(node.enum)) + parts.push(enumCheck(node.enum)); + if (Object.hasOwn(node, "const")) + parts.push(constCheck(node.const)); + if (Array.isArray(node.allOf)) + parts.push(and(node.allOf.map((s) => this.check(s, base)))); + if (Array.isArray(node.anyOf)) + parts.push(this.union(node.anyOf, base, false)); + if (Array.isArray(node.oneOf)) + parts.push(this.union(node.oneOf, base, true)); + if (node.not !== void 0) + parts.push(notCheck(this.check(node.not, base))); + if (node.if !== void 0 && (node.then !== void 0 || node.else !== void 0)) { + const then = node.then === void 0 ? ALWAYS : this.check(node.then, base); + const otherwise = node.else === void 0 ? ALWAYS : this.check(node.else, base); + parts.push(ifCheck(this.check(node.if, base), then, otherwise)); + } + if (typeof node.$ref === "string") + parts.push(this.ref(node.$ref, base)); + if (this.draft !== "7" && typeof node.$dynamicRef === "string") { + parts.push(this.dynamicRef(node.$dynamicRef, base)); + } + } + union(branches, base, exactlyOne) { + const checks = () => branches.map((s) => this.check(s, base)); + return constUnion(branches, exactlyOne) ?? this.tagged(branches, base) ?? (exactlyOne ? oneCheck(checks()) : anyCheck(checks())); + } + ref(ref, base) { + const target = this.r.resolve(ref, base); + const check = this.check(target.node, target.base); + return this.dynamic && target.base !== base ? scopedCheck(this.scope, target.base, check) : check; + } + dynamicRef(ref, base) { + const resolved = this.bookended(ref, base); + if (resolved === void 0) + return this.ref(ref, base); + const { initial, name } = resolved; + const fallback = this.check(initial.node, initial.base); + const lookup = this.dynamicLookup(name, (node, b) => this.check(node, b)); + const scope = this.scope; + return (v) => { + for (let i = 0; i < scope.length; i++) { + const check = lookup(scope[i]); + if (check !== null) + return check(v); + } + return fallback(v); + }; + } + /** The initial target and anchor name of a `$dynamicRef` that resolves dynamically, or undefined for a plain ref. */ + bookended(ref, base) { + const initial = this.r.resolve(ref, base); + const uri = resolveUri(ref, base); + const name = uri.slice(documentOf(uri).length + 1); + const anchored = isSchemaObject(initial.node) && initial.node.$dynamicAnchor === name; + if (name === "" || name.startsWith("/") || !anchored) + return void 0; + if (!this.dynamic) + throw RESTART; + return { initial, name }; + } + // Resolved at run time against the dynamic scope, so a schema with a bookended $dynamicRef keeps its compiler. + dynamicLookup(name, compile2) { + const found = /* @__PURE__ */ new Map(); + return (uri) => { + const key = `${uri}#${name}`; + let check = found.get(key); + if (check === void 0) { + const target = this.r.dynamicAnchors.get(key); + check = target === void 0 ? null : compile2(target, this.r.baseOf.get(target) ?? uri); + found.set(key, check); + } + return check; + }; + } + /** anyOf/oneOf whose branches are all objects with a distinct required const on one key: the tag picks the branch. */ + tagged(branches, base) { + if (branches.length < 2) + return void 0; + const resolved = []; + for (const branch of branches) { + if (!isSchemaObject(branch)) + return void 0; + const ref = typeof branch.$ref === "string" && Object.keys(branch).length === 1 ? branch.$ref : void 0; + const node = ref === void 0 ? branch : this.r.resolve(ref, this.r.baseFor(branch, base)).node; + if (!isSchemaObject(node)) + return void 0; + resolved.push(node); + } + const first = resolved[0].properties; + if (!isSchemaObject(first)) + return void 0; + for (const key of Object.keys(first)) { + const tags = resolved.map((s) => tagOf(s, key)); + if (tags.some((t) => t === void 0) || new Set(tags).size !== tags.length) + continue; + return taggedCheck(key, tags, branches.map((s) => this.check(s, base))); + } + return void 0; + } + stringGroup(node, strict) { + const min = number(node.minLength) ?? 0; + const max = number(node.maxLength) ?? Number.POSITIVE_INFINITY; + const re = typeof node.pattern === "string" ? sharedRegex(node.pattern) : void 0; + const format = this.formats !== void 0 && typeof node.format === "string" && Object.hasOwn(this.formats, node.format) ? this.formats[node.format] : void 0; + if (min === 0 && max === Number.POSITIVE_INFINITY && re === void 0 && format === void 0) + return void 0; + return stringCheck(strict, min, max, re, format); + } + numberGroup(node, mode) { + const min = number(node.minimum); + const max = number(node.maximum); + const xmin = number(node.exclusiveMinimum); + const xmax = number(node.exclusiveMaximum); + const multipleOf = number(node.multipleOf); + if ([min, max, xmin, xmax, multipleOf].every((x) => x === void 0)) + return void 0; + const inf = Number.POSITIVE_INFINITY; + return numberCheck(mode, min ?? -inf, max ?? inf, xmin ?? -inf, xmax ?? inf, multipleOf); + } + objectGroup(node, base, strict) { + const onlyCore = OBJECT_EXTRAS.every((k) => node[k] === void 0); + const core = this.objectCore(node, base, onlyCore ? strict ? GUARD_STRICT : GUARD_LOOSE : GUARD_NONE); + if (core !== void 0 && onlyCore) + return core; + const parts = core === void 0 ? [] : [core]; + if (node.propertyNames !== void 0) + parts.push(propertyNamesCheck(this.check(node.propertyNames, base))); + const minProperties = number(node.minProperties); + const maxProperties = number(node.maxProperties); + if (minProperties !== void 0 || maxProperties !== void 0) { + parts.push(propertyCountCheck(minProperties ?? 0, maxProperties ?? Number.POSITIVE_INFINITY)); + } + const dependentRequired = []; + const dependentSchemas = []; + if (this.draft !== "7") { + for (const [k, list] of entries(node.dependentRequired)) + if (Array.isArray(list)) + dependentRequired.push([k, list]); + for (const [k, s] of entries(node.dependentSchemas)) + dependentSchemas.push([k, this.check(s, base)]); + } + for (const [k, d] of entries(node.dependencies)) { + if (Array.isArray(d)) + dependentRequired.push([k, d]); + else + dependentSchemas.push([k, this.check(d, base)]); + } + if (dependentRequired.length > 0) + parts.push(dependentRequiredCheck(dependentRequired)); + if (dependentSchemas.length > 0) + parts.push(dependentSchemasCheck(dependentSchemas)); + if (parts.length === 0) + return strict ? IS_OBJECT : void 0; + return guardObject(and(parts), strict); + } + objectCore(node, base, guard) { + const properties = isSchemaObject(node.properties) ? node.properties : {}; + const required = Array.isArray(node.required) ? node.required.filter((k) => typeof k === "string") : []; + const patterns = isSchemaObject(node.patternProperties) ? node.patternProperties : {}; + const additional = node.additionalProperties; + const keys = Object.keys(properties); + const patternKeys = Object.keys(patterns); + if (keys.length + required.length + patternKeys.length === 0 && (additional === void 0 || additional === true)) { + return void 0; + } + const entries2 = []; + for (const k of keys) { + const check = this.check(properties[k], base); + const flags = (LEAF_CODES.get(check) ?? 0) | (required.includes(k) ? REQUIRED : 0) | (k in Object.prototype ? INHERITED : 0); + entries2.push(k, check, flags); + } + const extraRequired = required.filter((k) => !Object.hasOwn(properties, k)); + const pats = patternKeys.map((p) => [sharedRegex(p), this.check(patterns[p], base)]); + const extra = additional === void 0 || additional === true ? void 0 : this.check(additional, base); + if (pats.length === 0 && extraRequired.length === 0 && (extra === void 0 || additional === false)) { + const requiredCount = keys.filter((k) => required.includes(k)).length; + return declaredObject(entries2, requiredCount, additional === false, guard); + } + return openObject(entries2, keys, extraRequired, pats, extra, guard); + } + arrayGroup(node, base, strict) { + let prefix = []; + let rest; + if (Array.isArray(node.items)) { + prefix = node.items; + rest = node.additionalItems; + } else { + if (this.draft !== "7" && Array.isArray(node.prefixItems)) + prefix = node.prefixItems; + rest = node.items; + } + const prefixChecks = prefix.map((s) => this.check(s, base)); + const restCheck = rest === void 0 || rest === true ? void 0 : this.check(rest, base); + const minItems = number(node.minItems); + const maxItems = number(node.maxItems); + if (node.contains === void 0 && node.uniqueItems !== true && (prefixChecks.length > 0 || restCheck !== void 0)) { + const guard = strict ? GUARD_STRICT : GUARD_LOOSE; + return listCheck(guard, minItems ?? 0, maxItems ?? Number.POSITIVE_INFINITY, prefixChecks, restCheck); + } + const parts = []; + if (prefixChecks.length > 0 || restCheck !== void 0) + parts.push(itemsCheck(prefixChecks, restCheck)); + if (minItems !== void 0 || maxItems !== void 0) { + parts.push(lengthCheck(minItems ?? 0, maxItems ?? Number.POSITIVE_INFINITY)); + } + if (node.contains !== void 0) { + const min = this.draft === "7" ? 1 : number(node.minContains) ?? 1; + const max = this.draft === "7" ? Number.POSITIVE_INFINITY : number(node.maxContains) ?? Number.POSITIVE_INFINITY; + parts.push(containsCheck(this.check(node.contains, base), min, max)); + } + if (node.uniqueItems === true) + parts.push(uniqueCheck); + if (parts.length === 0) + return strict ? IS_ARRAY : void 0; + return guardArray(and(parts), strict); + } + /** The annotating check of a schema evaluated in place (only below `unevaluatedProperties`/`unevaluatedItems`). */ + annotating(node, base) { + if (node === true) + return ANNOTATING_TRUE; + if (node === false) + return ANNOTATING_FALSE; + if (!isSchemaObject(node)) + throw new Error(`A schema must be an object or a boolean, got ${JSON.stringify(node)}`); + const cached = this.annotatingCache.get(node); + if (cached !== void 0) + return cached; + const slot = { check: void 0 }; + this.annotatingCache.set(node, indirectAnnotating(slot)); + const check = this.buildAnnotating(node, this.r.baseFor(node, base)); + slot.check = check; + this.annotatingCache.set(node, check); + return check; + } + buildAnnotating(node, base) { + const rest = {}; + let annotates = false; + for (const k of Object.keys(node)) { + if (ANNOTATING.has(k)) + annotates = true; + else + rest[k] = node[k]; + } + const plain = this.plain(rest, base); + const parts = []; + if (annotates) + this.annotatingParts(node, base, parts); + const all = parts.length === 0 ? ignoreAnnotations(plain) : annotateAll(plain, parts); + const own = node.unevaluatedProperties !== void 0 || node.unevaluatedItems !== void 0 ? isolateAnnotations(all) : all; + return this.dynamic && this.r.isResource(node, base) ? scopedAnnotating(this.scope, base, own) : own; + } + annotatingParts(node, base, parts) { + if (node.properties !== void 0 || node.patternProperties !== void 0 || node.additionalProperties !== void 0) { + const props = entries(node.properties).map(([k, s]) => [k, this.check(s, base)]); + const pats = entries(node.patternProperties).map(([p, s]) => [sharedRegex(p), this.check(s, base)]); + const extra = node.additionalProperties === void 0 ? void 0 : this.check(node.additionalProperties, base); + parts.push(annotateObject(props, pats, extra)); + } + if (node.prefixItems !== void 0 || node.items !== void 0 || node.contains !== void 0) { + const prefix = Array.isArray(node.prefixItems) ? node.prefixItems : Array.isArray(node.items) ? node.items : []; + const rest = Array.isArray(node.items) ? node.additionalItems : node.items; + parts.push(annotateArray(prefix.map((s) => this.check(s, base)), rest === void 0 ? void 0 : this.check(rest, base), node.contains === void 0 ? void 0 : this.check(node.contains, base), number(node.minContains) ?? 1, number(node.maxContains) ?? Number.POSITIVE_INFINITY)); + } + if (Array.isArray(node.allOf)) + for (const s of node.allOf) + parts.push(this.annotating(s, base)); + if (Array.isArray(node.anyOf)) + parts.push(annotateAny(node.anyOf.map((s) => this.annotating(s, base)), false)); + if (Array.isArray(node.oneOf)) + parts.push(annotateAny(node.oneOf.map((s) => this.annotating(s, base)), true)); + if (node.if !== void 0) { + const then = node.then === void 0 ? void 0 : this.annotating(node.then, base); + const otherwise = node.else === void 0 ? void 0 : this.annotating(node.else, base); + parts.push(annotateIf(this.annotating(node.if, base), then, otherwise)); + } + if (typeof node.$ref === "string") + parts.push(this.annotatingRef(node.$ref, base)); + if (typeof node.$dynamicRef === "string") + parts.push(this.annotatingDynamicRef(node.$dynamicRef, base)); + for (const [k, s] of entries(node.dependentSchemas)) + parts.push(annotateDependent(k, this.annotating(s, base))); + if (node.unevaluatedProperties !== void 0) { + parts.push(unevaluatedProperties(this.check(node.unevaluatedProperties, base))); + } + if (node.unevaluatedItems !== void 0) + parts.push(unevaluatedItems(this.check(node.unevaluatedItems, base))); + } + annotatingRef(ref, base) { + const target = this.r.resolve(ref, base); + const check = this.annotating(target.node, target.base); + return this.dynamic && target.base !== base ? scopedAnnotating(this.scope, target.base, check) : check; + } + annotatingDynamicRef(ref, base) { + const resolved = this.bookended(ref, base); + if (resolved === void 0) + return this.annotatingRef(ref, base); + const { initial, name } = resolved; + const fallback = this.annotating(initial.node, initial.base); + const lookup = this.dynamicLookup(name, (node, b) => this.annotating(node, b)); + const scope = this.scope; + return (v, a) => { + for (let i = 0; i < scope.length; i++) { + const check = lookup(scope[i]); + if (check !== null) + return check(v, a); + } + return fallback(v, a); + }; + } +}; +var NEUTRAL_KEYWORDS = /* @__PURE__ */ new Set([ + "$schema", + "$comment", + "title", + "description", + "default", + "examples", + "deprecated", + "readOnly", + "writeOnly", + "$defs", + "definitions", + "contentEncoding", + "contentMediaType", + "minContains", + "maxContains", + "$vocabulary" +]); +var OBJECT_EXTRAS = [ + "propertyNames", + "minProperties", + "maxProperties", + "dependentRequired", + "dependentSchemas", + "dependencies" +]; +var ANNOTATING = /* @__PURE__ */ new Set([ + "properties", + "patternProperties", + "additionalProperties", + "prefixItems", + "items", + "additionalItems", + "contains", + "minContains", + "maxContains", + "allOf", + "anyOf", + "oneOf", + "if", + "then", + "else", + "$ref", + "$dynamicRef", + "dependentSchemas", + "unevaluatedProperties", + "unevaluatedItems" +]); +function constUnion(branches, exactlyOne) { + const values = []; + for (const branch of branches) { + if (!isSchemaObject(branch) || !Object.hasOwn(branch, "const")) + return void 0; + for (const k of Object.keys(branch)) + if (k !== "const" && !NEUTRAL_KEYWORDS.has(k)) + return void 0; + if (typeof branch.const === "object" && branch.const !== null) + return void 0; + if (exactlyOne && values.includes(branch.const)) + return void 0; + values.push(branch.const); + } + return enumCheck(values); +} +function tagOf(branch, key) { + const properties = branch.properties; + if (branch.type !== "object" || !Array.isArray(branch.required) || !branch.required.includes(key)) + return void 0; + const tag = isSchemaObject(properties) ? properties[key] : void 0; + if (!isSchemaObject(tag) || !Object.hasOwn(tag, "const")) + return void 0; + return typeof tag.const === "object" && tag.const !== null ? void 0 : tag.const; +} +function number(value2) { + return typeof value2 === "number" ? value2 : void 0; +} +function entries(value2) { + return isSchemaObject(value2) ? Object.entries(value2) : []; +} + +// node_modules/@earendil-works/pi-schema/dist/explain.js +var Explainer = class { + c; + schema; + /** + * The errors of `$ref` targets for object values, within one errors() call: a recursive union explains each branch + * to pick the one to blame, and every branch would explain the same children again, exponentially in the depth. + */ + memo = void 0; + constructor(compiler2, schema) { + this.c = compiler2; + this.schema = schema; + compiler2.root(); + } + /** The errors of `value`, at least one (`value` failed the check). */ + errors(value2) { + const out = []; + try { + this.walk(this.schema, this.c.r.rootBase, value2, "", out); + } finally { + this.memo = void 0; + } + if (out.length === 0) + out.push({ path: "", keyword: "schema", message: "invalid" }); + return out; + } + ok(node, base, v) { + return this.c.check(node, base)(v); + } + // For $dynamicRef schemas this check runs outside the original dynamic scope, so their errors are approximate. + walk(node, base, v, path, out) { + if (node === true) + return; + if (node === false) { + out.push({ path, keyword: "false", message: "no value is allowed here" }); + return; + } + if (!isSchemaObject(node)) + return; + const b = this.c.r.baseFor(node, base); + if (this.ok(node, b, v)) + return; + const start = out.length; + const push = (keyword, message, at = path) => { + out.push({ path: at, keyword, message }); + }; + if (this.c.draft === "7" && typeof node.$ref === "string") { + this.walkRef(node.$ref, b, v, path, out); + return; + } + if (node.type !== void 0) { + const types = Array.isArray(node.type) ? node.type : [node.type]; + const checks = types.map((t) => (typeof t === "string" ? TYPE_CHECKS.get(t) : void 0) ?? NEVER); + if (!checks.some((check) => check(v))) { + push("type", `expected ${types.join(" or ")}, got ${typeName(v)}`); + return; + } + } + if (Array.isArray(node.enum) && !enumCheck(node.enum)(v)) + push("enum", `expected one of ${listValues(node.enum)}`); + if (Object.hasOwn(node, "const") && !constCheck(node.const)(v)) + push("const", `expected ${JSON.stringify(node.const)}`); + if (typeof v === "string" && node.type !== "bytes") + this.walkString(node, v, push); + if (v instanceof Uint8Array && node.type === "bytes") + this.walkBytes(node, v, push); + if (typeof v === "number") + this.walkNumber(node, v, push); + if (isObject(v)) + this.walkObject(node, b, v, path, out, push); + if (Array.isArray(v)) + this.walkArray(node, b, v, path, out, push); + if (Array.isArray(node.allOf)) + for (const s of node.allOf) + this.walk(s, b, v, path, out); + if (Array.isArray(node.anyOf)) + this.walkUnion(node.anyOf, b, v, path, out, false); + if (Array.isArray(node.oneOf)) + this.walkUnion(node.oneOf, b, v, path, out, true); + if (node.not !== void 0 && this.ok(node.not, b, v)) + push("not", "must not match the schema in not"); + if (node.if !== void 0) { + const branch = this.ok(node.if, b, v) ? node.then : node.else; + if (branch !== void 0) + this.walk(branch, b, v, path, out); + } + if (typeof node.$ref === "string") + this.walkRef(node.$ref, b, v, path, out); + if (out.length === start && (node.unevaluatedProperties !== void 0 || node.unevaluatedItems !== void 0)) { + this.walkUnevaluated(node, b, v, path, out); + } + if (out.length === start && typeof node.$dynamicRef === "string") { + push("$dynamicRef", "does not match the dynamically referenced schema"); + } + } + walkRef(ref, base, v, path, out) { + const target = this.c.r.resolve(ref, base); + if (target.node === false && this.c.r.isUnresolved(ref, base)) { + out.push({ path, keyword: "$ref", message: `unresolved reference ${ref}` }); + return; + } + if (!isSchemaObject(target.node) || typeof v !== "object" || v === null) { + this.walk(target.node, target.base, v, path, out); + return; + } + this.memo ??= /* @__PURE__ */ new Map(); + let values = this.memo.get(target.node); + const known = values?.get(v); + if (known !== void 0 && known.path === path) { + out.push(...known.errors); + return; + } + const errors = []; + this.walk(target.node, target.base, v, path, errors); + if (values === void 0) { + values = /* @__PURE__ */ new Map(); + this.memo.set(target.node, values); + } + values.set(v, { path, errors }); + out.push(...errors); + } + walkString(node, v, push) { + const n = codePoints(v); + if (typeof node.minLength === "number" && n < node.minLength) { + push("minLength", `expected at least ${node.minLength} characters`); + } + if (typeof node.maxLength === "number" && n > node.maxLength) { + push("maxLength", `expected at most ${node.maxLength} characters`); + } + if (typeof node.pattern === "string" && !sharedRegex(node.pattern).test(v)) { + push("pattern", `expected to match ${node.pattern}`); + } + const formats2 = this.c.formats; + const format = formats2 !== void 0 && typeof node.format === "string" && Object.hasOwn(formats2, node.format) ? formats2[node.format] : void 0; + if (format !== void 0 && !format(v)) + push("format", `expected format ${node.format}`); + } + walkBytes(node, v, push) { + if (typeof node.minLength === "number" && v.length < node.minLength) { + push("minLength", `expected at least ${node.minLength} bytes`); + } + if (typeof node.maxLength === "number" && v.length > node.maxLength) { + push("maxLength", `expected at most ${node.maxLength} bytes`); + } + } + walkNumber(node, v, push) { + if (typeof node.minimum === "number" && v < node.minimum) + push("minimum", `expected >= ${node.minimum}`); + if (typeof node.maximum === "number" && v > node.maximum) + push("maximum", `expected <= ${node.maximum}`); + if (typeof node.exclusiveMinimum === "number" && v <= node.exclusiveMinimum) { + push("exclusiveMinimum", `expected > ${node.exclusiveMinimum}`); + } + if (typeof node.exclusiveMaximum === "number" && v >= node.exclusiveMaximum) { + push("exclusiveMaximum", `expected < ${node.exclusiveMaximum}`); + } + if (typeof node.multipleOf === "number" && !isMultiple(v, node.multipleOf)) { + push("multipleOf", `expected a multiple of ${node.multipleOf}`); + } + } + walkObject(node, b, v, path, out, push) { + const properties = isSchemaObject(node.properties) ? node.properties : {}; + const required = Array.isArray(node.required) ? node.required : []; + for (const k of required) { + if (typeof k === "string" && (!Object.hasOwn(v, k) || v[k] === void 0)) + push("required", "missing", pointer(path, k)); + } + for (const k of Object.keys(properties)) { + if (Object.hasOwn(v, k) && v[k] !== void 0) + this.walk(properties[k], b, v[k], pointer(path, k), out); + } + const patterns = isSchemaObject(node.patternProperties) ? Object.entries(node.patternProperties) : []; + for (const k of Object.keys(v)) { + let matched = Object.hasOwn(properties, k); + for (const [p, s] of patterns) { + if (sharedRegex(p).test(k)) { + matched = true; + this.walk(s, b, v[k], pointer(path, k), out); + } + } + if (!matched && node.additionalProperties !== void 0) { + if (node.additionalProperties === false) + push("additionalProperties", "unknown field", pointer(path, k)); + else + this.walk(node.additionalProperties, b, v[k], pointer(path, k), out); + } + if (node.propertyNames !== void 0 && !this.ok(node.propertyNames, b, k)) { + push("propertyNames", "invalid property name", pointer(path, k)); + } + } + const count = Object.keys(v).length; + if (typeof node.minProperties === "number" && count < node.minProperties) { + push("minProperties", `expected at least ${node.minProperties} properties`); + } + if (typeof node.maxProperties === "number" && count > node.maxProperties) { + push("maxProperties", `expected at most ${node.maxProperties} properties`); + } + const dependencies = { + ...this.c.draft === "7" || !isSchemaObject(node.dependentRequired) ? {} : node.dependentRequired, + ...isSchemaObject(node.dependencies) ? node.dependencies : {} + }; + for (const [k, d] of Object.entries(dependencies)) { + if (!Object.hasOwn(v, k)) + continue; + if (!Array.isArray(d)) + this.walk(d, b, v, path, out); + else + for (const r of d) + if (!Object.hasOwn(v, r)) + push("dependentRequired", `required when ${k} is present`, pointer(path, r)); + } + if (this.c.draft !== "7" && isSchemaObject(node.dependentSchemas)) { + for (const [k, s] of Object.entries(node.dependentSchemas)) + if (Object.hasOwn(v, k)) + this.walk(s, b, v, path, out); + } + } + walkArray(node, b, v, path, out, push) { + let prefix = []; + let rest; + if (Array.isArray(node.items)) { + prefix = node.items; + rest = node.additionalItems; + } else { + if (this.c.draft !== "7" && Array.isArray(node.prefixItems)) + prefix = node.prefixItems; + rest = node.items; + } + for (let i = 0; i < v.length; i++) { + const s = i < prefix.length ? prefix[i] : rest; + if (s !== void 0) + this.walk(s, b, v[i], `${path}/${i}`, out); + } + if (typeof node.minItems === "number" && v.length < node.minItems) { + push("minItems", `expected at least ${node.minItems} items`); + } + if (typeof node.maxItems === "number" && v.length > node.maxItems) { + push("maxItems", `expected at most ${node.maxItems} items`); + } + if (node.uniqueItems === true && !uniqueCheck(v)) + push("uniqueItems", "expected unique items"); + if (node.contains !== void 0) { + const draft7 = this.c.draft === "7"; + const min = draft7 || typeof node.minContains !== "number" ? 1 : node.minContains; + const max = draft7 || typeof node.maxContains !== "number" ? Number.POSITIVE_INFINITY : node.maxContains; + if (!containsCheck(this.c.check(node.contains, b), min, max)(v)) { + push("contains", containsMessage(min, max)); + } + } + } + walkUnion(branches, b, v, path, out, exactlyOne) { + const matches = branches.filter((s) => this.ok(s, b, v)).length; + if (matches === 1 || !exactlyOne && matches > 0) + return; + const keyword = exactlyOne ? "oneOf" : "anyOf"; + if (matches > 1) { + out.push({ path, keyword, message: "matches more than one alternative" }); + return; + } + const tag = this.tagOf(branches, b); + if (tag !== void 0 && isObject(v)) { + const i = tag.values.indexOf(v[tag.key]); + if (i < 0) + out.push({ + path: pointer(path, tag.key), + keyword, + message: `expected one of ${listValues(tag.values)}` + }); + else + this.walk(branches[i], b, v, path, out); + return; + } + let best; + for (const s of branches) { + const errors = []; + this.walk(s, b, v, path, errors); + if (errors.length === 0) + continue; + const declared = isObject(v) ? this.declaredKeys(s, b, v) : 0; + const better = best === void 0 || declared > best.declared || declared === best.declared && errors[0].path.length > best.errors[0].path.length; + if (better) + best = { errors, declared }; + } + out.push(...best?.errors ?? [{ path, keyword, message: "matches no alternative" }]); + } + /** How many of the keys of `v` the branch `s` (through a `$ref`) declares in `properties`. */ + declaredKeys(s, b, v) { + const node = isSchemaObject(s) && typeof s.$ref === "string" ? this.c.r.resolve(s.$ref, b).node : s; + const properties = isSchemaObject(node) && isSchemaObject(node.properties) ? node.properties : {}; + return Object.keys(v).filter((k) => Object.hasOwn(properties, k)).length; + } + tagOf(branches, b) { + const resolved = branches.map((s) => isSchemaObject(s) && typeof s.$ref === "string" ? this.c.r.resolve(s.$ref, b).node : s); + const first = resolved[0]; + if (!isSchemaObject(first) || !isSchemaObject(first.properties)) + return void 0; + for (const key of Object.keys(first.properties)) { + const values = resolved.map((s) => { + const tag = isSchemaObject(s) && isSchemaObject(s.properties) ? s.properties[key] : void 0; + return isSchemaObject(tag) ? tag.const : void 0; + }); + const primitive = values.every((x) => x !== void 0 && (typeof x !== "object" || x === null)); + if (primitive && new Set(values).size === values.length) + return { key, values }; + } + return void 0; + } + walkUnevaluated(node, b, v, path, out) { + const { unevaluatedProperties: unevaluatedProperties2, unevaluatedItems: unevaluatedItems2, ...rest } = node; + const a = newAnnotations(); + this.c.annotating(rest, b)(v, a); + if (isObject(v) && unevaluatedProperties2 !== void 0 && !a.allProps) { + for (const k of Object.keys(v)) { + if (a.props?.has(k)) + continue; + if (unevaluatedProperties2 === false) { + out.push({ path: pointer(path, k), keyword: "unevaluatedProperties", message: "unknown field" }); + } else + this.walk(unevaluatedProperties2, b, v[k], pointer(path, k), out); + } + } + if (Array.isArray(v) && unevaluatedItems2 !== void 0 && !a.allItems) { + for (let i = a.items; i < v.length; i++) { + if (a.indexes?.has(i)) + continue; + if (unevaluatedItems2 === false) { + out.push({ path: `${path}/${i}`, keyword: "unevaluatedItems", message: "unexpected item" }); + } else + this.walk(unevaluatedItems2, b, v[i], `${path}/${i}`, out); + } + } + } +}; +var LISTED_VALUES = 20; +function listValues(values) { + if (values.length <= LISTED_VALUES) + return JSON.stringify(values); + const listed = JSON.stringify(values.slice(0, LISTED_VALUES)); + return `${listed.slice(0, -1)}, ... and ${values.length - LISTED_VALUES} more]`; +} +function containsMessage(min, max) { + if (max === Number.POSITIVE_INFINITY) + return `expected at least ${min} matching ${min === 1 ? "item" : "items"}`; + if (min === 0) + return `expected at most ${max} matching ${max === 1 ? "item" : "items"}`; + return `expected between ${min} and ${max} matching items`; +} +function pointer(path, key) { + return `${path}/${String(key).replace(/~/g, "~0").replace(/\//g, "~1")}`; +} +function typeName(v) { + if (v === null) + return "null"; + if (Array.isArray(v)) + return "array"; + if (v instanceof Uint8Array) + return "bytes"; + if (typeof v === "number" && Number.isInteger(v)) + return "integer"; + return typeof v; +} + +// node_modules/@earendil-works/pi-schema/dist/validator.js +function compile(schema, options = NO_OPTIONS) { + const check = compileCheck(schema, options); + return options.coerce === true ? new CoercingValidator(schema, options, check) : new Validator(schema, options, check); +} +var NO_OPTIONS = Object.freeze({}); +var Validator = class { + /** Whether `value` is valid. A plain function: it may be passed around without its validator. */ + check; + schema; + options; + explainer = void 0; + constructor(schema, options, check) { + this.check = check; + this.schema = schema; + this.options = options; + } + /** + * Why `value` is invalid: one error per failing keyword, `[]` when it is valid. Built on the first failure and + * kept, so a validator whose values always pass never pays for it. + */ + errors(value2) { + if (this.check(value2)) + return []; + this.explainer ??= new Explainer(compiler(this.schema, this.options), this.schema); + return this.explainer.errors(value2); + } +}; +var CoercingValidator = class extends Validator { + coercer = void 0; + /** + * `value` coerced towards the schema: numeric strings to numbers, `"true"` to `true`, a single value to a one-item + * array, an optional `null` dropped, the first union branch the value converts to (the README lists every rule). + * Only the changed paths are copied; `value` comes back itself when nothing changes, and is never modified. Values + * that cannot be coerced stay as they are. The rules are built on the first call. + */ + coerce(value2) { + this.coercer ??= new Coercer(compiler(this.schema, this.options), this.schema); + return this.coercer.coerce(value2); + } + /** Coerces `value`, then checks it: the coerced value when it is valid, else its errors. */ + parse(value2) { + const coerced = this.coerce(value2); + return this.check(coerced) ? { ok: true, value: coerced } : { ok: false, errors: this.errors(coerced) }; + } +}; +function compileCheck(schema, options) { + return compiler(schema, options).root(); +} +function compiler(schema, options) { + const plain = new Compiler(schema, options, false); + try { + plain.root(); + return plain; + } catch (error) { + if (error !== RESTART) + throw error; + return new Compiler(schema, options, true); + } +} + +// node_modules/@earendil-works/chord/dist/json.js +var DATA_DESCRIPTOR = { + value: void 0, + writable: true, + enumerable: true, + configurable: true +}; +function copyJson(value2, options) { + return copy(value2, void 0, options?.omitUndefinedProperties === true); +} +function copy(value2, ancestors, omitUndefinedProperties) { + if (value2 === null || typeof value2 === "string" || typeof value2 === "boolean") + return value2; + if (typeof value2 === "number") { + if (Number.isFinite(value2)) + return value2; + throw new TypeError("Value contains a non-finite number and is not strict JSON"); + } + if (typeof value2 !== "object") + throw new TypeError(`Value contains a non-JSON ${typeof value2}; expected strict JSON`); + const active = ancestors ?? /* @__PURE__ */ new Set(); + if (active.has(value2)) + throw new TypeError("Value contains cycles and is not strict JSON"); + active.add(value2); + try { + if (Array.isArray(value2)) { + if (Object.getPrototypeOf(value2) !== Array.prototype || Reflect.ownKeys(value2).length !== value2.length + 1) { + throw new TypeError("Value must contain strict JSON dense plain arrays"); + } + const result2 = new Array(value2.length); + for (let index = 0; index < value2.length; index++) { + const descriptor = Object.getOwnPropertyDescriptor(value2, index); + if (descriptor === void 0 || !descriptor.enumerable || !("value" in descriptor)) { + throw new TypeError("Value must contain strict JSON enumerable indexed data properties"); + } + defineData(result2, String(index), copy(descriptor.value, active, omitUndefinedProperties)); + } + return result2; + } + const prototype = Object.getPrototypeOf(value2); + if (prototype !== Object.prototype && prototype !== null) { + throw new TypeError("Value must contain strict JSON plain objects or arrays"); + } + const result = Object.create(prototype); + for (const key of Reflect.ownKeys(value2)) { + if (typeof key === "symbol") + throw new TypeError("Value contains a symbol key and is not strict JSON"); + const descriptor = Object.getOwnPropertyDescriptor(value2, key); + if (!descriptor.enumerable || !("value" in descriptor)) { + throw new TypeError("Value must contain strict JSON enumerable data properties"); + } + if (descriptor.value === void 0 && omitUndefinedProperties) + continue; + defineData(result, key, copy(descriptor.value, active, omitUndefinedProperties)); + } + return result; + } finally { + active.delete(value2); + } +} +function defineData(target, key, value2) { + DATA_DESCRIPTOR.value = value2; + Object.defineProperty(target, key, DATA_DESCRIPTOR); + DATA_DESCRIPTOR.value = void 0; +} + +// node_modules/@earendil-works/chord/dist/delta/apply-immutable-trusted.js +var DATA_DESCRIPTOR2 = { + value: void 0, + writable: true, + enumerable: true, + configurable: true +}; +function applyImmutableTrusted(target, operations) { + let root2 = target; + const owned = /* @__PURE__ */ new WeakSet(); + for (const operation of operations) { + if (operation[0] === "r") { + root2 = operation[1]; + continue; + } + if (operation[0] === "p" || operation[0] === "m") { + const copied2 = copyPath(root2, operation[1], operation[1].length, owned); + root2 = copied2.root; + if (!Array.isArray(copied2.target)) + throw new TypeError("Trusted array operation target is not an array"); + if (operation[0] === "p") + spliceTrusted(copied2.target, operation[2], operation[3], operation[4]); + else + permuteTrusted(copied2.target, operation[2]); + continue; + } + const path = operation[1]; + const copied = copyPath(root2, path, path.length - 1, owned); + root2 = copied.root; + const key = path[path.length - 1]; + switch (operation[0]) { + case "s": + defineData2(copied.target, key, operation[2]); + break; + case "d": + if (Array.isArray(copied.target)) { + if (typeof key !== "number") + throw new TypeError("Trusted array deletion key is not numeric"); + spliceTrusted(copied.target, key, 1, []); + } else + Reflect.deleteProperty(copied.target, key); + break; + case "a": { + const current = read(copied.target, key); + if (typeof current !== "string") + throw new TypeError("Trusted append target is not a string"); + defineData2(copied.target, key, `${current}${operation[2]}`); + break; + } + case "t": { + const current = read(copied.target, key); + if (typeof current !== "string") + throw new TypeError("Trusted truncate target is not a string"); + defineData2(copied.target, key, current.slice(operation[2])); + break; + } + } + } + return root2; +} +function copyPath(root2, path, length, owned) { + if (!isContainer(root2)) + throw new TypeError("Trusted operation root is not a container"); + let copiedRoot = root2; + if (!owned.has(root2)) { + copiedRoot = shallowCopy(root2); + owned.add(copiedRoot); + } + let destination = copiedRoot; + for (let index = 0; index < length; index++) { + const segment = path[index]; + const child = read(destination, segment); + if (!isContainer(child)) + throw new TypeError("Trusted operation path is not a container"); + if (owned.has(child)) { + destination = child; + continue; + } + const copy2 = shallowCopy(child); + defineData2(destination, segment, copy2); + owned.add(copy2); + destination = copy2; + } + return { root: copiedRoot, target: destination }; +} +function shallowCopy(value2) { + if (Array.isArray(value2)) + return Array.from(value2); + return Object.getPrototypeOf(value2) === null ? Object.assign(/* @__PURE__ */ Object.create(null), value2) : { ...value2 }; +} +function read(target, key) { + return target[key]; +} +function defineData2(target, key, value2) { + DATA_DESCRIPTOR2.value = value2; + Object.defineProperty(target, key, DATA_DESCRIPTOR2); + DATA_DESCRIPTOR2.value = void 0; +} +function spliceTrusted(target, start, remove, items) { + const oldLength = target.length; + const delta = items.length - remove; + if (delta > 0) { + target.length = oldLength + delta; + target.copyWithin(start + items.length, start + remove, oldLength); + } else if (delta < 0) { + target.copyWithin(start + items.length, start + remove, oldLength); + target.length = oldLength + delta; + } + for (let index = 0; index < items.length; index++) + defineData2(target, start + index, items[index]); +} +function permuteTrusted(target, permutation) { + if (target.length !== permutation.length) + throw new TypeError("Trusted permutation length mismatch"); + const previous = target.slice(); + for (let index = 0; index < permutation.length; index++) + target[index] = previous[permutation[index]]; +} +function isContainer(value2) { + return value2 !== null && typeof value2 === "object"; +} + +// node_modules/@earendil-works/chord/dist/delta/tracker.js +var NODE = /* @__PURE__ */ Symbol("chord.delta.overlay.node"); +var PREPARED = /* @__PURE__ */ new WeakMap(); +var RELEASED = {}; +var ARRAY_MUTATORS = /* @__PURE__ */ new Set([ + "push", + "pop", + "shift", + "unshift", + "splice", + "reverse", + "sort", + "fill", + "copyWithin" +]); +var MAX_DELTA_OPERATIONS = 4096; +var MAX_SIMPLE_OBJECT_NODES = 128; +var DATA_DESCRIPTOR3 = { + value: void 0, + writable: true, + enumerable: true, + configurable: true +}; +var PreparedImpl = class { + #context; + value; + base; + ops; + constructor(context, value2, operations) { + this.#context = context; + this.value = value2; + this.base = context.baseValue; + this.ops = operations; + PREPARED.set(this, context); + } + get baseRevision() { + return this.#context.baseRevision; + } + abort() { + abortContext(this.#context); + } +}; +var ChangeImpl = class { + #context; + #preparedStatus; + #settled = false; + constructor(context) { + this.#context = context; + } + get state() { + const state = this.#context?.root?.proxy; + if (state === void 0) + throw new TypeError("Cannot use a settled overlay"); + return state; + } + prepare() { + if (this.#settled) + throw new Error("Change has already been settled"); + const context = this.#context; + assertWritable(context); + context.status.value = "prepared"; + try { + if (!context.replacement) + context.ops = context.dirty.length === 0 ? [] : emitOperations(context); + const prepared = materializePrepared(context); + this.#preparedStatus = context.status; + this.#settled = true; + return prepared; + } catch (error) { + context.status.value = "aborted"; + clearContext(context); + this.#settled = true; + throw error; + } finally { + this.#context = void 0; + } + } + abort() { + if (this.#settled) { + if (this.#preparedStatus?.value === "prepared") + this.#preparedStatus.value = "aborted"; + this.#preparedStatus = void 0; + return; + } + this.#settled = true; + abortContext(this.#context); + this.#context = void 0; + } +}; +var TrackerImpl = class { + #owner = {}; + #open; + #competitors; + #selfRef; + #value; + #revision = 0; + #pruneBudget = 256; + constructor(initial) { + this.#value = initial; + this.#selfRef = new WeakRef(this); + } + get value() { + return this.#value; + } + get revision() { + return this.#revision; + } + beginChange() { + const context = createContext(this.#selfRef, this.#owner, this.#revision, this.#value, false, this.#value); + if (this.#open !== void 0) + this.#demote(this.#open); + this.#open = context; + return new ChangeImpl(context); + } + prepareReplace(value2) { + const context = createContext(this.#selfRef, this.#owner, this.#revision, value2, true, this.#value); + context.status.value = "prepared"; + try { + return materializePrepared(context); + } catch (error) { + context.status.value = "aborted"; + clearContext(context); + throw error; + } + } + adopt(prepared) { + const context = PREPARED.get(prepared); + if (context?.owner !== this.#owner) + throw new Error("Prepared change belongs to a different tracker"); + if (context.status.value === "consumed") + throw new Error("Prepared change has already been used"); + if (context.status.value === "aborted") + throw new Error("Prepared change has been aborted"); + if (context.status.value === "stale") + throw new Error("Prepared change is stale"); + if (context.status.value !== "prepared") + throw new Error("Prepared change is not ready"); + if (context.baseRevision !== this.#revision) { + context.status.value = "stale"; + clearContext(context); + throw new Error("Prepared change is stale"); + } + if (this.#value !== prepared.base) { + context.status.value = "stale"; + throw new Error("Prepared change is stale"); + } + this.#value = prepared.value; + context.status.value = "consumed"; + this.#revision += 1; + this.#invalidate(context); + } + releaseContext(context) { + if (this.#open === context) + this.#open = void 0; + else if (context.registryRef !== void 0) + this.#competitors?.delete(context.registryRef); + context.registryRef = void 0; + } + #demote(context) { + const reference = new WeakRef(context); + context.registryRef = reference; + this.#competitors ??= /* @__PURE__ */ new Set(); + this.#competitors.add(reference); + this.#pruneBudget -= 1; + if (this.#pruneBudget === 0) { + for (const entry2 of this.#competitors) { + if (entry2.deref() === void 0) + this.#competitors.delete(entry2); + } + this.#pruneBudget = Math.max(256, this.#competitors.size); + } + } + #invalidate(winner) { + const open = this.#open; + const competitors = this.#competitors; + this.#open = void 0; + this.#competitors = void 0; + this.#pruneBudget = 256; + if (open !== void 0) + staleCompetitor(open, winner); + if (competitors === void 0) + return; + for (const reference of competitors) { + const context = reference.deref(); + if (context !== void 0) + staleCompetitor(context, winner); + } + } + replacementBase(context) { + return context.baseRevision === this.#revision ? this.#value : void 0; + } +}; +function staleCompetitor(context, winner) { + if (context === winner) + return; + if (context.status.value === "open" || context.status.value === "prepared") + context.status.value = "stale"; + context.registryRef = void 0; + releaseOverlayReferences(context); +} +function track(initial) { + return new TrackerImpl(initial); +} +function appendText(draft, key, text) { + const node = draft[NODE]; + if (node === void 0) + throw new TypeError("appendText() needs a draft"); + assertWritable(node.context); + const name = String(key); + const current = Array.isArray(nodeBase(node)) || !objectHas(node, name) ? void 0 : objectValue(node, name); + if (typeof current !== "string") + throw new TypeError(`appendText() needs a string at ${JSON.stringify(name)}`); + if (text.length === 0) + return; + const owned = ownedSlice2(text, 0); + const appended = node.appends?.get(name) ?? (hasObjectWrite(node, name) ? void 0 : ""); + setObjectWrite(node, name, current + owned); + markDirty(node); + if (appended !== void 0) { + node.appends ??= /* @__PURE__ */ new Map(); + node.appends.set(name, appended + owned); + } +} +function materializePrepared(context) { + const operations = ensureOperations(context); + const base = context.baseValue; + const value2 = operations.length === 0 ? base : context.simpleObjectMaterialization ? cloneNode(context.root) : materializeOperations(base, operations); + const prepared = new PreparedImpl(context, value2, operations); + if (context.nodes.length > 4096) + releaseOverlayReferences(context); + else + clearContext(context); + return prepared; +} +function materializeOperations(base, operations) { + for (const operation of operations) { + if (operation[0] === "p" || operation[0] === "m") + return applyImmutable(base, operations); + } + return applyImmutableTrusted(base, operations); +} +function createContext(tracker, owner, baseRevision, root2, replacement, base) { + const context = { + owner, + tracker, + baseRevision, + status: { value: "open" }, + root: void 0, + bases: [], + stored: void 0, + dirty: [], + nodes: [], + rawNodes: void 0, + ops: void 0, + replacement, + replacementNoop: false, + baseValue: base, + overlayReleased: false, + simpleObjectMaterialization: false, + registryRef: void 0 + }; + context.root = createNode(context, root2, void 0); + return context; +} +var sharedObjectHandler = { + deleteProperty(target, property) { + return deleteProperty(nodeForTarget(target), property); + }, + defineProperty(target) { + assertWritable(nodeForTarget(target).context); + throw new TypeError("Defining overlay properties is not supported"); + }, + get(target, property) { + if (property === "then") { + const node2 = target[NODE]; + if (node2 === void 0 || isSettledContext(node2.context)) + return void 0; + } + const node = nodeForTarget(target); + if (property === NODE) + return node; + return getProperty(node, property); + }, + getOwnPropertyDescriptor(target, property) { + return getDescriptor(nodeForTarget(target), property); + }, + getPrototypeOf(target) { + const node = nodeForTarget(target); + assertReadable(node.context); + return Object.getPrototypeOf(nodeBase(node)); + }, + has(target, property) { + return hasProperty(nodeForTarget(target), property); + }, + isExtensible(target) { + assertReadable(nodeForTarget(target).context); + return true; + }, + ownKeys(target) { + return ownKeys(nodeForTarget(target)); + }, + preventExtensions(target) { + assertWritable(nodeForTarget(target).context); + throw new TypeError("Overlays cannot be made non-extensible"); + }, + set(target, property, value2) { + return setProperty(nodeForTarget(target), property, value2); + }, + setPrototypeOf(target) { + assertWritable(nodeForTarget(target).context); + throw new TypeError("Changing an overlay prototype is not supported"); + } +}; +var sharedArrayHandler = sharedObjectHandler; +function createNode(context, base, parent, parentKind = 0, parentKey = "", parentSource = void 0, parentPlacement = false) { + const existing = context.rawNodes?.get(base); + if (existing !== void 0) + return existing; + const target = Array.isArray(base) ? [] : {}; + const baseIndex = context.bases.length; + const parentIndex = parent?.baseIndex ?? -1; + context.bases.push(base); + const node = { + context, + baseIndex, + parentIndex, + parentKind, + parentKey, + parentPlacement, + target, + proxy: target + }; + if (parentSource !== void 0) + node.parentSource = parentSource; + target[NODE] = node; + node.proxy = new Proxy(target, Array.isArray(base) ? sharedArrayHandler : sharedObjectHandler); + if (parent !== void 0) { + context.rawNodes ??= /* @__PURE__ */ new WeakMap(); + context.rawNodes.set(base, node); + } + context.nodes.push(node); + return node; +} +function nodeBase(node) { + return node.context.bases[node.baseIndex]; +} +function nodeParent(node) { + return node.parentIndex < 0 ? void 0 : node.context.nodes[node.parentIndex]; +} +function storeValue(context, value2) { + if (!isContainer2(value2)) + return value2; + context.stored ??= []; + const index = context.stored.length; + context.stored.push(value2); + return { index }; +} +function storedValue(context, reference) { + return typeof reference === "object" && reference !== null ? context.stored[reference.index] : reference; +} +function replaceStoredValue(context, reference, value2) { + if (isContainer2(value2)) { + if (typeof reference === "object" && reference !== null) { + context.stored[reference.index] = value2; + return reference; + } + return storeValue(context, value2); + } + if (typeof reference === "object" && reference !== null) + context.stored[reference.index] = RELEASED; + return value2; +} +function releaseStoredValue(context, reference) { + if (typeof reference === "object" && reference !== null) + context.stored[reference.index] = RELEASED; +} +function nodeForTarget(target) { + const node = target[NODE]; + if (node === void 0) + throw new TypeError("Cannot use a settled overlay"); + return node; +} +function isSettledContext(context) { + return context.overlayReleased || context.status.value === "consumed" || context.status.value === "aborted" || context.status.value === "stale"; +} +function assertReadable(context) { + if (isSettledContext(context)) + throw new TypeError("Cannot use a settled overlay"); +} +function assertWritable(context) { + assertReadable(context); + if (context.status.value !== "open") + throw new TypeError("Prepared overlays are read-only"); +} +function getProperty(node, property) { + assertReadable(node.context); + if (Array.isArray(nodeBase(node))) { + const overlay = arrayOverlay(node); + if (property === "length") + return arrayLength(overlay); + if (ARRAY_MUTATORS.has(property)) + return arrayMutators[property]; + const index = arrayIndex(property); + if (index !== void 0) + return getArrayIndex(node, index); + return Reflect.get(Array.prototype, property, node.proxy); + } + if (typeof property === "symbol") + return Reflect.get(nodeBase(node), property, node.proxy); + const key = String(property); + if (!objectHas(node, key)) { + if (isObjectDeleted(node, key) || Object.hasOwn(nodeBase(node), key)) + return void 0; + return Reflect.get(nodeBase(node), property, node.proxy); + } + const value2 = objectValue(node, key); + if (!isContainer2(value2)) + return value2; + return createNode(node.context, value2, node, 0, key, void 0, hasObjectWrite(node, key)).proxy; +} +function getArrayIndex(node, index) { + const overlay = arrayOverlay(node); + if (index >= arrayLength(overlay)) + return void 0; + const piece = locatePiece(overlay, index); + const sourceIndex = piece.start + piece.step * overlay.locatedOffset; + const value2 = entryValueAt(node, piece, sourceIndex); + if (!isContainer2(value2)) + return value2; + return createNode(node.context, value2, node, piece.kind === "base" ? 1 : 2, sourceIndex, piece.kind === "insert" ? piece.source : void 0, piece.kind === "insert" || hasEntryOverrideAt(overlay, piece, sourceIndex)).proxy; +} +function setProperty(node, property, supplied) { + assertWritable(node.context); + if (typeof property === "symbol") + throw new TypeError("Symbol writes are not supported"); + if (Array.isArray(nodeBase(node))) { + if (property === "length") { + setArrayLength(node, toArrayLength(supplied)); + return true; + } + const index = arrayIndex(property); + if (index === void 0) + throw new TypeError("Only array indices and length can be written"); + if (index > arrayLength(arrayOverlay(node))) + throw new TypeError("Overlay arrays cannot contain holes"); + setArrayIndex(node, index, clonePlacement(supplied)); + return true; + } + const key = String(property); + if (supplied === void 0) + return deleteProperty(node, key); + const stored = clonePlacement(supplied); + const current = objectValue(node, key); + const wasDeleted = isObjectDeleted(node, key); + if (!wasDeleted && !isContainer2(stored) && current === stored) + return true; + node.appends?.delete(key); + setObjectWrite(node, key, stored); + if (wasDeleted && Object.hasOwn(nodeBase(node), key)) { + if (node.readded === void 0) + node.readded = /* @__PURE__ */ new Set(); + node.readded.add(key); + } + deleteObjectDeletion(node, key); + markDirty(node); + return true; +} +function deleteProperty(node, property) { + assertWritable(node.context); + if (typeof property === "symbol") + throw new TypeError("Symbol writes are not supported"); + if (Array.isArray(nodeBase(node))) + throw new TypeError("Overlay arrays cannot contain holes"); + const key = String(property); + if (!objectHas(node, key)) + return true; + node.appends?.delete(key); + deleteObjectWrite(node, key); + node.readded?.delete(key); + setObjectDeletion(node, key); + markDirty(node); + return true; +} +function hasProperty(node, property) { + assertReadable(node.context); + if (Array.isArray(nodeBase(node))) { + if (property === "length") + return true; + const index = arrayIndex(property); + if (index !== void 0) + return index < arrayLength(arrayOverlay(node)); + return property in Array.prototype; + } + return typeof property === "symbol" ? property in nodeBase(node) : objectHas(node, String(property)); +} +function ownKeys(node) { + assertReadable(node.context); + if (Array.isArray(nodeBase(node))) { + const length = arrayLength(arrayOverlay(node)); + const keys2 = new Array(length + 1); + for (let index = 0; index < length; index++) + keys2[index] = String(index); + keys2[length] = "length"; + return keys2; + } + let existingKeysOnly = node.deleteKey === void 0 && node.deletes === void 0 && node.readded === void 0 && (node.writeKey === void 0 || Object.hasOwn(nodeBase(node), node.writeKey)); + if (existingKeysOnly && node.writes !== void 0) { + for (const key of node.writes.keys()) { + if (!Object.hasOwn(nodeBase(node), key)) { + existingKeysOnly = false; + break; + } + } + } + if (existingKeysOnly) + return Object.keys(nodeBase(node)); + const keys = Object.keys(nodeBase(node)).filter((key) => !isObjectDeleted(node, key) && !node.readded?.has(key)); + const seen = new Set(keys); + if (node.writeKey !== void 0 && !seen.has(node.writeKey)) { + keys.push(node.writeKey); + seen.add(node.writeKey); + } + if (node.writes !== void 0) { + for (const key of node.writes.keys()) { + if (seen.has(key)) + continue; + keys.push(key); + seen.add(key); + } + } + const indices = []; + const strings = []; + for (const key of keys) { + const index = arrayIndex(key); + if (index === void 0) + strings.push(key); + else + indices.push(index); + } + indices.sort((left, right) => left - right); + return [...indices.map(String), ...strings]; +} +function getDescriptor(node, property) { + assertReadable(node.context); + if (Array.isArray(nodeBase(node))) { + if (property === "length") { + const length = arrayLength(arrayOverlay(node)); + node.target.length = length; + return Reflect.getOwnPropertyDescriptor(node.target, "length"); + } + const index = arrayIndex(property); + if (index === void 0 || index >= arrayLength(arrayOverlay(node))) + return void 0; + } else { + if (typeof property === "symbol" || !objectHas(node, String(property))) + return void 0; + } + return { + configurable: true, + enumerable: true, + writable: node.context.status.value === "open", + value: getProperty(node, property) + }; +} +function hasObjectWrite(node, key) { + return node.writeKey === key || (node.writes?.has(key) ?? false); +} +function setObjectWrite(node, key, value2) { + if (node.writes !== void 0) { + const reference = node.writes.get(key); + node.writes.set(key, reference === void 0 ? storeValue(node.context, value2) : replaceStoredValue(node.context, reference, value2)); + return; + } + if (node.writeKey === void 0 || node.writeKey === key) { + node.writeKey = key; + node.writeValue = node.writeValue === void 0 ? storeValue(node.context, value2) : replaceStoredValue(node.context, node.writeValue, value2); + return; + } + node.writes = /* @__PURE__ */ new Map(); + node.writes.set(node.writeKey, node.writeValue); + node.writes.set(key, storeValue(node.context, value2)); + node.writeKey = void 0; + node.writeValue = void 0; +} +function deleteObjectWrite(node, key) { + if (node.writeKey === key) { + node.writeKey = void 0; + releaseStoredValue(node.context, node.writeValue); + node.writeValue = void 0; + } else { + const reference = node.writes?.get(key); + if (reference !== void 0) + releaseStoredValue(node.context, reference); + node.writes?.delete(key); + } +} +function isObjectDeleted(node, key) { + return node.deleteKey === key || (node.deletes?.has(key) ?? false); +} +function setObjectDeletion(node, key) { + if (node.deletes !== void 0) { + node.deletes.add(key); + return; + } + if (node.deleteKey === void 0 || node.deleteKey === key) { + node.deleteKey = key; + return; + } + node.deletes = /* @__PURE__ */ new Set(); + node.deletes.add(node.deleteKey); + node.deletes.add(key); + node.deleteKey = void 0; +} +function deleteObjectDeletion(node, key) { + if (node.deleteKey === key) + node.deleteKey = void 0; + else + node.deletes?.delete(key); +} +function objectHas(node, key) { + if (isObjectDeleted(node, key)) + return false; + return hasObjectWrite(node, key) || Object.hasOwn(nodeBase(node), key); +} +function objectValue(node, key) { + if (node.writeKey === key) + return storedValue(node.context, node.writeValue); + const reference = node.writes?.get(key); + if (reference !== void 0) + return storedValue(node.context, reference); + return nodeBase(node)[key]; +} +function markDirty(node) { + if (node.dirty) + return; + node.dirty = true; + node.context.dirty.push(node); + for (let parent = nodeParent(node); parent !== void 0; parent = nodeParent(parent)) + parent.subtreeDirty = true; +} +function arrayOverlay(node) { + if (node.array !== void 0) + return node.array; + const base = nodeBase(node); + const overlay = { + root: void 0, + pieces: void 0, + baseOverrides: void 0, + insertOverrides: void 0, + structural: false, + generation: 0, + plan: void 0, + seed: 2654435769, + locatedOffset: 0, + baseLocations: void 0, + insertLocations: void 0 + }; + if (base.length > 0) + overlay.root = createPieceNode(overlay, { kind: "base", start: 0, length: base.length, step: 1 }); + node.array = overlay; + return overlay; +} +function baseOverridesForWrite(overlay) { + if (overlay.baseOverrides === void 0) + overlay.baseOverrides = /* @__PURE__ */ new Map(); + return overlay.baseOverrides; +} +function insertOverridesForWrite(overlay) { + if (overlay.insertOverrides === void 0) + overlay.insertOverrides = /* @__PURE__ */ new Map(); + return overlay.insertOverrides; +} +function nextPiecePriority(overlay) { + let value2 = overlay.seed; + value2 ^= value2 << 13; + value2 ^= value2 >>> 17; + value2 ^= value2 << 5; + overlay.seed = value2 >>> 0; + return overlay.seed; +} +function treeElements(node) { + return node?.elements ?? 0; +} +function updatePieceNode(node) { + node.elements = treeElements(node.left) + node.piece.length + treeElements(node.right); +} +function createPieceNode(overlay, piece) { + return { piece, left: void 0, right: void 0, priority: nextPiecePriority(overlay), elements: piece.length }; +} +function mergePieceTrees(left, right) { + if (left === void 0) + return right; + if (right === void 0) + return left; + if (left.priority >= right.priority) { + left.right = mergePieceTrees(left.right, right); + updatePieceNode(left); + return left; + } + right.left = mergePieceTrees(left, right.left); + updatePieceNode(right); + return right; +} +function splitPieceTree(overlay, root2, index) { + if (root2 === void 0) + return [void 0, void 0]; + const leftLength = treeElements(root2.left); + if (index < leftLength) { + const [left, right] = splitPieceTree(overlay, root2.left, index); + root2.left = right; + updatePieceNode(root2); + return [left, root2]; + } + const pieceEnd = leftLength + root2.piece.length; + if (index > pieceEnd) { + const [left, right] = splitPieceTree(overlay, root2.right, index - pieceEnd); + root2.right = left; + updatePieceNode(root2); + return [root2, right]; + } + if (index === leftLength) { + const left = root2.left; + root2.left = void 0; + updatePieceNode(root2); + return [left, root2]; + } + if (index === pieceEnd) { + const right = root2.right; + root2.right = void 0; + updatePieceNode(root2); + return [root2, right]; + } + const offset = index - leftLength; + const first = { ...root2.piece, length: offset }; + const second = { + ...root2.piece, + start: root2.piece.start + root2.piece.step * offset, + length: root2.piece.length - offset + }; + return [ + mergePieceTrees(root2.left, createPieceNode(overlay, first)), + mergePieceTrees(createPieceNode(overlay, second), root2.right) + ]; +} +function leftmostPieceNode(node) { + while (node.left !== void 0) + node = node.left; + return node; +} +function rightmostPieceNode(node) { + while (node.right !== void 0) + node = node.right; + return node; +} +function mergeablePieces(left, right) { + if (left.kind !== right.kind) + return false; + if (left.kind === "insert" && left.source !== right.source) + return false; + if (left.length === 1 && right.length === 1) + return Math.abs(right.start - left.start) === 1; + return left.step === right.step && left.start + left.step * left.length === right.start; +} +function joinNormalized(overlay, left, right) { + if (left === void 0) + return right; + if (right === void 0) + return left; + const leftPiece = rightmostPieceNode(left).piece; + const rightPiece = leftmostPieceNode(right).piece; + if (!mergeablePieces(leftPiece, rightPiece)) + return mergePieceTrees(left, right); + const [leftRest] = splitPieceTree(overlay, left, treeElements(left) - leftPiece.length); + const [, rightRest] = splitPieceTree(overlay, right, rightPiece.length); + const step = leftPiece.length === 1 ? rightPiece.start - leftPiece.start : leftPiece.step; + const combined = leftPiece.kind === "base" ? { kind: "base", start: leftPiece.start, length: leftPiece.length + rightPiece.length, step } : { + kind: "insert", + source: leftPiece.source, + start: leftPiece.start, + length: leftPiece.length + rightPiece.length, + step + }; + return joinNormalized(overlay, joinNormalized(overlay, leftRest, createPieceNode(overlay, combined)), rightRest); +} +function flattenPieceTree(node, output) { + if (node === void 0) + return; + flattenPieceTree(node.left, output); + output.push(node.piece); + flattenPieceTree(node.right, output); +} +function piecesOf(overlay) { + if (overlay.pieces === void 0) { + overlay.pieces = []; + flattenPieceTree(overlay.root, overlay.pieces); + } + return overlay.pieces; +} +function treeFromPieces(overlay, pieces) { + mergePieces(pieces); + let root2; + for (const piece of pieces) + root2 = mergePieceTrees(root2, createPieceNode(overlay, piece)); + return root2; +} +function replaceAllPieces(overlay, pieces) { + overlay.root = treeFromPieces(overlay, pieces); + overlay.pieces = void 0; + overlay.baseLocations = void 0; + overlay.insertLocations = void 0; +} +function arrayLength(overlay) { + return treeElements(overlay.root); +} +function locatePiece(overlay, index) { + let node = overlay.root; + while (node !== void 0) { + const leftLength = treeElements(node.left); + if (index < leftLength) + node = node.left; + else if (index >= leftLength + node.piece.length) { + index -= leftLength + node.piece.length; + node = node.right; + } else { + overlay.locatedOffset = index - leftLength; + return node.piece; + } + } + throw new RangeError("Array overlay index is out of range"); +} +function arrayIndex(property) { + if (typeof property !== "string" || property.length === 0 || property.length > 10) + return void 0; + if (property === "0") + return 0; + const first = property.charCodeAt(0); + if (first < 49 || first > 57) + return void 0; + let index = first - 48; + for (let offset = 1; offset < property.length; offset++) { + const digit = property.charCodeAt(offset) - 48; + if (digit < 0 || digit > 9) + return void 0; + index = index * 10 + digit; + if (index >= 4294967295) + return void 0; + } + return index; +} +function entryValueAt(node, piece, sourceIndex) { + const overlay = arrayOverlay(node); + if (piece.kind === "base") { + const valueIndex = overlay.baseOverrides?.get(sourceIndex); + return valueIndex === void 0 ? nodeBase(node)[sourceIndex] : storedValue(node.context, valueIndex); + } + const overrides = overlay.insertOverrides?.get(piece.source); + const reference = overrides?.has(sourceIndex) ? overrides.get(sourceIndex) : piece.source.refs[sourceIndex]; + return storedValue(node.context, reference); +} +function hasEntryOverrideAt(overlay, piece, sourceIndex) { + return piece.kind === "base" ? overlay.baseOverrides?.has(sourceIndex) ?? false : overlay.insertOverrides?.get(piece.source)?.has(sourceIndex) ?? false; +} +function extendRightmostPiece(node, amount) { + if (node.right !== void 0) + extendRightmostPiece(node.right, amount); + else + node.piece.length += amount; + updatePieceNode(node); +} +function invalidatePieceCaches(overlay) { + overlay.pieces = void 0; + overlay.baseLocations = void 0; + overlay.insertLocations = void 0; + overlay.plan = void 0; +} +function replacePieceRange(node, index, remove, inserted) { + if (remove === 0 && inserted.length === 0) + return; + const overlay = arrayOverlay(node); + if (remove === 0 && index === arrayLength(overlay) && inserted.length === 1 && overlay.root !== void 0) { + const addition = inserted[0]; + const tail = rightmostPieceNode(overlay.root).piece; + if (addition.kind === "insert" && tail.kind === "insert" && tail.step === 1 && tail.start + tail.length === tail.source.refs.length) { + for (let offset = 0; offset < addition.length; offset++) { + tail.source.refs.push(addition.source.refs[addition.start + offset]); + } + extendRightmostPiece(overlay.root, addition.length); + invalidatePieceCaches(overlay); + overlay.structural = true; + overlay.generation += 1; + markDirty(node); + return; + } + } + const [left, rest] = splitPieceTree(overlay, overlay.root, index); + const [, right] = splitPieceTree(overlay, rest, remove); + const middle = treeFromPieces(overlay, inserted); + overlay.root = joinNormalized(overlay, joinNormalized(overlay, left, middle), right); + invalidatePieceCaches(overlay); + overlay.structural = true; + overlay.generation += 1; + markDirty(node); +} +function mergePieces(pieces) { + for (let index = 1; index < pieces.length; ) { + const left = pieces[index - 1]; + const right = pieces[index]; + const sameSource = left.kind === right.kind && (left.kind === "base" || left.source === right.source); + if (sameSource && left.length === 1 && right.length === 1 && Math.abs(right.start - left.start) === 1) { + left.step = right.start - left.start; + left.length = 2; + pieces.splice(index, 1); + } else if (sameSource && left.step === right.step && left.start + left.step * left.length === right.start) { + left.length += right.length; + pieces.splice(index, 1); + } else + index += 1; + } +} +function insertPiece(node, items, start = 0) { + if (items.length === start) + return []; + const refs = []; + for (let index = start; index < items.length; index++) + refs.push(storeValue(node.context, items[index])); + return [{ kind: "insert", source: { refs }, start: 0, length: refs.length, step: 1 }]; +} +function insertPlacementPiece(node, values, start = 0) { + if (values.length === start) + return []; + const storedLength = node.context.stored?.length ?? 0; + try { + for (let index = start; index < values.length; index++) + values[index] = storeValue(node.context, clonePlacement(values[index])); + } catch (error) { + if (node.context.stored !== void 0) + node.context.stored.length = storedLength; + throw error; + } + return [ + { + kind: "insert", + source: { refs: values }, + start, + length: values.length - start, + step: 1 + } + ]; +} +function setArrayIndex(node, index, stored) { + const overlay = arrayOverlay(node); + const length = arrayLength(overlay); + if (index === length) { + replacePieceRange(node, length, 0, insertPiece(node, [stored])); + return; + } + const piece = locatePiece(overlay, index); + const sourceIndex = piece.start + piece.step * overlay.locatedOffset; + const current = entryValueAt(node, piece, sourceIndex); + if (!isContainer2(stored) && current === stored) + return; + if (piece.kind === "base") { + const existingIndex = overlay.baseOverrides?.get(sourceIndex); + if (!isContainer2(stored) && stored === nodeBase(node)[sourceIndex]) { + if (existingIndex !== void 0) + releaseStoredValue(node.context, existingIndex); + overlay.baseOverrides?.delete(sourceIndex); + } else if (existingIndex === void 0) { + baseOverridesForWrite(overlay).set(sourceIndex, storeValue(node.context, stored)); + } else + overlay.baseOverrides.set(sourceIndex, replaceStoredValue(node.context, existingIndex, stored)); + } else { + let overrides = overlay.insertOverrides?.get(piece.source); + const existingIndex = overrides?.get(sourceIndex); + if (!isContainer2(stored) && stored === storedValue(node.context, piece.source.refs[sourceIndex])) { + if (existingIndex !== void 0) + releaseStoredValue(node.context, existingIndex); + overrides?.delete(sourceIndex); + if (overrides?.size === 0) + overlay.insertOverrides?.delete(piece.source); + } else { + if (overrides === void 0) { + overrides = /* @__PURE__ */ new Map(); + insertOverridesForWrite(overlay).set(piece.source, overrides); + } + if (existingIndex === void 0) + overrides.set(sourceIndex, storeValue(node.context, stored)); + else + overrides.set(sourceIndex, replaceStoredValue(node.context, existingIndex, stored)); + } + } + markDirty(node); +} +function setArrayLength(node, next) { + const current = arrayLength(arrayOverlay(node)); + if (next === current) + return; + if (next < current) + replacePieceRange(node, next, current - next, []); + else + replacePieceRange(node, current, 0, insertPiece(node, Array.from({ length: next - current }, () => null))); +} +function toArrayLength(value2) { + const number2 = Number(value2); + if (!Number.isInteger(number2) || number2 < 0 || number2 >= 4294967296) + throw new RangeError("Invalid array length"); + return number2; +} +function toIntegerOrInfinity(value2) { + const number2 = Number(value2); + if (Number.isNaN(number2) || number2 === 0) + return 0; + return Number.isFinite(number2) ? Math.trunc(number2) : number2; +} +function clampIndex(value2, length) { + if (value2 === Number.NEGATIVE_INFINITY) + return 0; + if (value2 < 0) + return Math.max(length + value2, 0); + return Math.min(value2, length); +} +function mutatorNode(receiver) { + if (!isContainer2(receiver)) + return void 0; + const node = Reflect.get(receiver, NODE); + if (node === void 0) + return void 0; + if (!Array.isArray(nodeBase(node))) + throw new TypeError("Array mutator called on incompatible receiver"); + assertWritable(node.context); + return node; +} +var arrayMutators = { + push(...items) { + const node = mutatorNode(this); + if (node === void 0) + return Reflect.apply(Array.prototype.push, this, items); + const length = arrayLength(arrayOverlay(node)); + replacePieceRange(node, length, 0, insertPlacementPiece(node, items)); + return length + items.length; + }, + pop() { + const node = mutatorNode(this); + if (node === void 0) + return Reflect.apply(Array.prototype.pop, this, []); + const length = arrayLength(arrayOverlay(node)); + if (length === 0) + return void 0; + const value2 = getArrayIndex(node, length - 1); + replacePieceRange(node, length - 1, 1, []); + return value2; + }, + shift() { + const node = mutatorNode(this); + if (node === void 0) + return Reflect.apply(Array.prototype.shift, this, []); + const length = arrayLength(arrayOverlay(node)); + if (length === 0) + return void 0; + const value2 = getArrayIndex(node, 0); + replacePieceRange(node, 0, 1, []); + return value2; + }, + unshift(...items) { + const node = mutatorNode(this); + if (node === void 0) + return Reflect.apply(Array.prototype.unshift, this, items); + replacePieceRange(node, 0, 0, insertPlacementPiece(node, items)); + return arrayLength(arrayOverlay(node)); + }, + splice(...args) { + const node = mutatorNode(this); + if (node === void 0) + return Reflect.apply(Array.prototype.splice, this, args); + const length = arrayLength(arrayOverlay(node)); + const start = args.length === 0 ? 0 : clampIndex(toIntegerOrInfinity(args[0]), length); + const remove = args.length === 0 ? 0 : args.length === 1 ? length - start : Math.min(Math.max(toIntegerOrInfinity(args[1]), 0), length - start); + const removed = Array.from({ length: remove }, (_, offset) => getArrayIndex(node, start + offset)); + const itemStart = Math.min(2, args.length); + const itemCount = Math.max(args.length - 2, 0); + replacePieceRange(node, start, remove, insertPlacementPiece(node, args, itemStart)); + setArrayLength(node, length - remove + itemCount); + return removed; + }, + reverse() { + const node = mutatorNode(this); + if (node === void 0) + return Reflect.apply(Array.prototype.reverse, this, []); + const overlay = arrayOverlay(node); + if (arrayLength(overlay) < 2) + return node.proxy; + const pieces = [...piecesOf(overlay)].reverse(); + for (const piece of pieces) { + piece.start += piece.step * (piece.length - 1); + piece.step = piece.step === 1 ? -1 : 1; + } + replaceAllPieces(overlay, pieces); + overlay.structural = true; + overlay.generation += 1; + overlay.plan = void 0; + markDirty(node); + return node.proxy; + }, + sort(comparator) { + const node = mutatorNode(this); + if (node === void 0) + return Reflect.apply(Array.prototype.sort, this, [comparator]); + if (comparator !== void 0 && typeof comparator !== "function") + throw new TypeError("Comparator must be a function"); + const overlay = arrayOverlay(node); + const insertedSources = []; + const insertedIndices = []; + const insertedValues = []; + const baseValues = new Array(nodeBase(node).length); + const order = []; + for (const piece of piecesOf(overlay)) { + for (let offset = 0; offset < piece.length; offset++) { + const sourceIndex = piece.start + piece.step * offset; + if (piece.kind === "base") { + order.push(sourceIndex); + baseValues[sourceIndex] = publicSortValue(node, sourceIndex, insertedSources, insertedIndices); + } else { + insertedSources.push(piece.source); + insertedIndices.push(sourceIndex); + const token = -insertedSources.length; + order.push(token); + insertedValues.push(publicSortValue(node, token, insertedSources, insertedIndices)); + } + } + } + const baseSnapshot = /* @__PURE__ */ new Map(); + for (const [index, valueIndex] of overlay.baseOverrides ?? []) + baseSnapshot.set(index, storedValue(node.context, valueIndex)); + const insertSnapshots = /* @__PURE__ */ new Map(); + for (const [source, overrides] of overlay.insertOverrides ?? []) { + const snapshot = /* @__PURE__ */ new Map(); + for (const [index, valueIndex] of overrides) + snapshot.set(index, storedValue(node.context, valueIndex)); + insertSnapshots.set(source, snapshot); + } + const generation = overlay.generation; + order.sort((left, right) => { + const leftValue = left < 0 ? insertedValues[-left - 1] : baseValues[left]; + const rightValue = right < 0 ? insertedValues[-right - 1] : baseValues[right]; + if (typeof comparator === "function") + return Number(comparator(leftValue, rightValue)); + const a = String(leftValue); + const b = String(rightValue); + return a < b ? -1 : a > b ? 1 : 0; + }); + if (baseSnapshot.size > 0 || insertSnapshots.size > 0 || (overlay.baseOverrides?.size ?? 0) > 0 || (overlay.insertOverrides?.size ?? 0) > 0) { + for (const token of order) { + restoreSortOverride(node, token, insertedSources, insertedIndices, baseSnapshot, insertSnapshots); + } + } + const comparatorWasStructural = overlay.generation !== generation; + const currentLength = arrayLength(overlay); + const samePrefix = currentLength >= order.length && order.every((token, index) => sameSortTokenAt(overlay, index, token, insertedSources, insertedIndices)); + if (!samePrefix) { + replacePieceRange(node, 0, Math.min(order.length, currentLength), piecesFromSortOrder(order, insertedSources, insertedIndices)); + } + if (comparatorWasStructural) + deduplicateArrayEntries(node); + return node.proxy; + }, + fill(supplied, startArg, endArg) { + const node = mutatorNode(this); + if (node === void 0) + return Reflect.apply(Array.prototype.fill, this, [supplied, startArg, endArg]); + const length = arrayLength(arrayOverlay(node)); + const start = startArg === void 0 ? 0 : clampIndex(toIntegerOrInfinity(startArg), length); + const end = endArg === void 0 ? length : clampIndex(toIntegerOrInfinity(endArg), length); + if (end <= start) + return node.proxy; + const items = Array.from({ length: end - start }, () => clonePlacement(supplied)); + replacePieceRange(node, start, end - start, insertPiece(node, items)); + return node.proxy; + }, + copyWithin(targetArg, startArg, endArg) { + const node = mutatorNode(this); + if (node === void 0) + return Reflect.apply(Array.prototype.copyWithin, this, [targetArg, startArg, endArg]); + const length = arrayLength(arrayOverlay(node)); + const target = clampIndex(toIntegerOrInfinity(targetArg), length); + const start = clampIndex(toIntegerOrInfinity(startArg), length); + const end = endArg === void 0 ? length : clampIndex(toIntegerOrInfinity(endArg), length); + const count = Math.min(Math.max(end - start, 0), length - target); + const values = Array.from({ length: count }, (_, offset) => clonePlacement(getArrayIndex(node, start + offset))); + replacePieceRange(node, target, count, insertPiece(node, values)); + return node.proxy; + } +}; +function sortTokenSource(token, sources) { + return token < 0 ? sources[-token - 1] : void 0; +} +function sortTokenIndex(token, indices) { + return token < 0 ? indices[-token - 1] : token; +} +function publicSortValue(node, token, sources, indices) { + const overlay = arrayOverlay(node); + const source = sortTokenSource(token, sources); + const sourceIndex = sortTokenIndex(token, indices); + const overrideIndex = source === void 0 ? overlay.baseOverrides?.get(sourceIndex) : overlay.insertOverrides?.get(source)?.get(sourceIndex); + const value2 = overrideIndex !== void 0 ? storedValue(node.context, overrideIndex) : source === void 0 ? nodeBase(node)[sourceIndex] : storedValue(node.context, source.refs[sourceIndex]); + if (!isContainer2(value2)) + return value2; + return createNode(node.context, value2, node, source === void 0 ? 1 : 2, sourceIndex, source, source !== void 0 || (overlay.baseOverrides?.has(sourceIndex) ?? false)).proxy; +} +function restoreSortOverride(node, token, sources, indices, baseSnapshot, insertSnapshots) { + const overlay = arrayOverlay(node); + const source = sortTokenSource(token, sources); + const sourceIndex = sortTokenIndex(token, indices); + if (source === void 0) { + const existingIndex2 = overlay.baseOverrides?.get(sourceIndex); + const snapshotValue2 = baseSnapshot.get(sourceIndex); + if (snapshotValue2 !== void 0) { + if (existingIndex2 === void 0) + baseOverridesForWrite(overlay).set(sourceIndex, storeValue(node.context, snapshotValue2)); + else + overlay.baseOverrides.set(sourceIndex, replaceStoredValue(node.context, existingIndex2, snapshotValue2)); + } else { + if (existingIndex2 !== void 0) + releaseStoredValue(node.context, existingIndex2); + overlay.baseOverrides?.delete(sourceIndex); + } + return; + } + let overrides = overlay.insertOverrides?.get(source); + const existingIndex = overrides?.get(sourceIndex); + const snapshotValue = insertSnapshots.get(source)?.get(sourceIndex); + if (snapshotValue !== void 0) { + if (overrides === void 0) { + overrides = /* @__PURE__ */ new Map(); + insertOverridesForWrite(overlay).set(source, overrides); + } + if (existingIndex === void 0) + overrides.set(sourceIndex, storeValue(node.context, snapshotValue)); + else + overrides.set(sourceIndex, replaceStoredValue(node.context, existingIndex, snapshotValue)); + } else { + if (existingIndex !== void 0) + releaseStoredValue(node.context, existingIndex); + overrides?.delete(sourceIndex); + if (overrides?.size === 0) + overlay.insertOverrides?.delete(source); + } +} +function sameSortTokenAt(overlay, logicalIndex, token, sources, indices) { + const piece = locatePiece(overlay, logicalIndex); + const sourceIndex = piece.start + piece.step * overlay.locatedOffset; + const tokenSource = sortTokenSource(token, sources); + return sourceIndex === sortTokenIndex(token, indices) && (piece.kind === "base" && tokenSource === void 0 || piece.kind === "insert" && piece.source === tokenSource); +} +function deduplicateArrayEntries(node) { + const overlay = arrayOverlay(node); + const seenBase = /* @__PURE__ */ new Set(); + const seenInsert = /* @__PURE__ */ new Map(); + const next = []; + let duplicated = false; + for (const piece of piecesOf(overlay)) { + for (let offset = 0; offset < piece.length; offset++) { + const sourceIndex = piece.start + piece.step * offset; + let seen; + if (piece.kind === "base") { + seen = seenBase.has(sourceIndex); + seenBase.add(sourceIndex); + } else { + let indices = seenInsert.get(piece.source); + if (indices === void 0) { + indices = /* @__PURE__ */ new Set(); + seenInsert.set(piece.source, indices); + } + seen = indices.has(sourceIndex); + indices.add(sourceIndex); + } + if (seen) { + duplicated = true; + appendMergedPiece(next, insertPiece(node, [clonePlacementStored(entryValueAt(node, piece, sourceIndex), node.context)])[0]); + } else + appendMergedPiece(next, singletonPiece(piece, sourceIndex)); + } + } + if (!duplicated) + return; + replaceAllPieces(overlay, next); + overlay.structural = true; + overlay.generation += 1; + overlay.plan = void 0; + markDirty(node); +} +function piecesFromSortOrder(order, sources, indices) { + const pieces = []; + for (const token of order) { + const source = token < 0 ? sources[-token - 1] : void 0; + const sourceIndex = token < 0 ? indices[-token - 1] : token; + const previous = pieces.at(-1); + const sameSource = previous !== void 0 && (source === void 0 && previous.kind === "base" || source !== void 0 && previous.kind === "insert" && previous.source === source); + if (previous !== void 0 && sameSource) { + if (previous.length === 1) { + const step = sourceIndex - previous.start; + if (step === 1 || step === -1) { + previous.step = step; + previous.length = 2; + continue; + } + } else if (previous.start + previous.step * previous.length === sourceIndex) { + previous.length += 1; + continue; + } + } + pieces.push(source === void 0 ? { kind: "base", start: sourceIndex, length: 1, step: 1 } : { kind: "insert", source, start: sourceIndex, length: 1, step: 1 }); + } + return pieces; +} +function appendMergedPiece(pieces, piece) { + const previous = pieces.at(-1); + const sameSource = previous !== void 0 && previous.kind === piece.kind && (previous.kind === "base" || previous.source === piece.source); + if (previous !== void 0 && sameSource && previous.length === 1 && piece.length === 1) { + const step = piece.start - previous.start; + if (step === 1 || step === -1) { + previous.step = step; + previous.length = 2; + return; + } + } + if (previous !== void 0 && sameSource && previous.step === piece.step && previous.start + previous.step * previous.length === piece.start) { + previous.length += piece.length; + } else + pieces.push(piece); +} +function singletonPiece(piece, sourceIndex) { + return piece.kind === "base" ? { kind: "base", start: sourceIndex, length: 1, step: 1 } : { kind: "insert", source: piece.source, start: sourceIndex, length: 1, step: 1 }; +} +function clonePlacement(value2) { + const proxyNode = isContainer2(value2) ? Reflect.get(value2, NODE) : void 0; + return proxyNode === void 0 ? copyJson(value2) : clonePlacementNode(proxyNode); +} +function cloneNode(node) { + assertReadable(node.context); + if (Array.isArray(nodeBase(node))) { + const overlay = arrayOverlay(node); + const result2 = []; + for (const piece of piecesOf(overlay)) { + for (let offset = 0; offset < piece.length; offset++) { + const sourceIndex = piece.start + piece.step * offset; + result2.push(cloneStored(entryValueAt(node, piece, sourceIndex), node.context)); + } + } + return result2; + } + const result = Object.create(Object.getPrototypeOf(nodeBase(node))); + for (const key of ownKeys(node)) + defineData3(result, key, cloneStored(objectValue(node, key), node.context)); + return result; +} +function cloneStored(value2, context) { + if (!isContainer2(value2)) + return value2; + const node = context.rawNodes?.get(value2); + return node === void 0 || !node.dirty && !node.subtreeDirty ? value2 : cloneNode(node); +} +function clonePlacementNode(node) { + assertReadable(node.context); + if (Array.isArray(nodeBase(node))) { + const overlay = arrayOverlay(node); + const result2 = []; + for (const piece of piecesOf(overlay)) { + for (let offset = 0; offset < piece.length; offset++) { + const sourceIndex = piece.start + piece.step * offset; + result2.push(clonePlacementStored(entryValueAt(node, piece, sourceIndex), node.context)); + } + } + return result2; + } + const result = Object.create(Object.getPrototypeOf(nodeBase(node))); + for (const key of ownKeys(node)) + defineData3(result, key, clonePlacementStored(objectValue(node, key), node.context)); + return result; +} +function clonePlacementStored(value2, context) { + if (!isContainer2(value2)) + return copyJson(value2); + const node = context.rawNodes?.get(value2); + return node === void 0 ? copyJson(value2) : clonePlacementNode(node); +} +function defineData3(target, key, value2) { + DATA_DESCRIPTOR3.value = value2; + Object.defineProperty(target, key, DATA_DESCRIPTOR3); + DATA_DESCRIPTOR3.value = void 0; +} +function emitOperations(context) { + const simple = emitSimpleObjectOperations(context); + if (simple !== void 0) + return simple; + const operations = []; + const forcedFolds = /* @__PURE__ */ new Map(); + const emissionPaths = /* @__PURE__ */ new Map(); + const denseIndices = /* @__PURE__ */ new Map(); + for (const node of context.dirty) { + recordDenseArrayPosition(node, denseIndices); + if (Array.isArray(nodeBase(node))) { + const overlay = arrayOverlay(node); + if (!overlay.structural && (overlay.baseOverrides?.size ?? 0) > 0) { + let candidates = denseIndices.get(node); + if (candidates === void 0) { + candidates = { indices: [], bits: void 0, length: nodeBase(node).length }; + denseIndices.set(node, candidates); + } + for (const index of overlay.baseOverrides.keys()) + addDenseCandidate(candidates, index); + } + } + } + const denseRegions = /* @__PURE__ */ new Map(); + for (const [array, candidates] of denseIndices) { + const path = resolvePath(array); + if (path === void 0 || path.some((segment) => typeof segment === "string" && RESERVED_SEGMENTS.has(segment))) { + continue; + } + const regions = buildDenseRegions(candidates); + if (regions.length > 0) + denseRegions.set(array, regions); + } + for (const node of context.dirty) { + const path = resolvePath(node); + if (path === void 0) + continue; + if (hasCoveringDenseRegion(node, path, denseRegions)) + continue; + emissionPaths.set(node, path); + if (!Array.isArray(nodeBase(node)) && hasReservedMutation(node)) + forcedFolds.set(node, path); + const reservedAt = path.findIndex((segment) => typeof segment === "string" && RESERVED_SEGMENTS.has(segment)); + if (reservedAt >= 0) { + let ancestor = node; + for (let depth = path.length; depth > reservedAt; depth--) + ancestor = nodeParent(ancestor); + forcedFolds.set(ancestor, path.slice(0, reservedAt)); + } + } + for (const [node, path] of forcedFolds) + emissionPaths.set(node, path); + for (const node of denseRegions.keys()) { + const path = resolvePath(node); + if (path !== void 0 && !hasCoveringDenseRegion(node, path, denseRegions)) + emissionPaths.set(node, path); + } + let maxDepth = 0; + for (const path of emissionPaths.values()) + maxDepth = Math.max(maxDepth, path.length); + const buckets = Array.from({ length: maxDepth + 1 }, () => []); + for (const [node, path] of emissionPaths) + buckets[path.length].push(node); + const folded = /* @__PURE__ */ new Set(); + for (const bucket of buckets) { + for (const node of bucket) { + const path = emissionPaths.get(node); + if (hasPlacementAncestor(node) || hasFoldedAncestor(node, folded)) + continue; + if (forcedFolds.has(node)) { + emitSet(operations, path, cloneNode(node)); + folded.add(node); + continue; + } + if (Array.isArray(nodeBase(node))) + emitArrayOperations(node, path, operations, denseRegions.get(node)); + else + emitObjectOperations(node, path, operations); + if (operations.length > MAX_DELTA_OPERATIONS) { + locatedDenseArray = void 0; + return [["r", cloneNode(context.root)]]; + } + } + } + locatedDenseArray = void 0; + return operations; +} +function emitSimpleObjectOperations(context) { + const nodes = []; + for (const node of context.dirty) { + if (Array.isArray(nodeBase(node)) || hasReservedMutation(node) || hasPlacementAncestor(node)) + return void 0; + for (let parent = nodeParent(node); parent !== void 0; parent = nodeParent(parent)) { + if (Array.isArray(nodeBase(parent))) + return void 0; + } + const path = resolvePath(node); + if (path === void 0) + continue; + for (const segment of path) { + if (typeof segment === "string" && RESERVED_SEGMENTS.has(segment)) + return void 0; + } + nodes.push(node); + if (nodes.length > MAX_SIMPLE_OBJECT_NODES) + return void 0; + } + for (let index = 1; index < nodes.length; index++) { + const node = nodes[index]; + const depth = node.preparedPath.length; + let at = index; + while (at > 0 && nodes[at - 1].preparedPath.length > depth) { + nodes[at] = nodes[at - 1]; + at -= 1; + } + nodes[at] = node; + } + const operations = []; + let canMaterializeDirectly = true; + for (const node of nodes) { + if (emitObjectOperations(node, node.preparedPath, operations)) + canMaterializeDirectly = false; + if (operations.length > MAX_DELTA_OPERATIONS) + return [["r", cloneNode(context.root)]]; + } + context.simpleObjectMaterialization = canMaterializeDirectly; + return operations; +} +var locatedDenseArray; +var locatedDenseIndex = 0; +function locateDenseArrayPosition(node) { + let child = node; + for (let parent = nodeParent(child); parent !== void 0; parent = nodeParent(child)) { + if (Array.isArray(nodeBase(parent))) { + const overlay = arrayOverlay(parent); + if (child.parentKind !== 1 || overlay.structural) + return false; + const sourceIndex = child.parentKey; + const valueIndex = overlay.baseOverrides?.get(sourceIndex); + const current = valueIndex === void 0 ? nodeBase(parent)[sourceIndex] : storedValue(parent.context, valueIndex); + if (current !== nodeBase(child)) + return false; + locatedDenseArray = parent; + locatedDenseIndex = sourceIndex; + return true; + } + child = parent; + } + return false; +} +function hasCoveringDenseRegion(node, path, denseRegions) { + for (let parent = nodeParent(node); parent !== void 0; parent = nodeParent(parent)) { + const regions = denseRegions.get(parent); + if (regions === void 0) + continue; + const parentPath = resolvePath(parent); + if (parentPath === void 0 || path.length <= parentPath.length) + continue; + let matches = true; + for (let index2 = 0; index2 < parentPath.length; index2++) { + if (path[index2] !== parentPath[index2]) { + matches = false; + break; + } + } + if (!matches) + continue; + const index = path[parentPath.length]; + if (typeof index === "number" && regionContaining(regions, index)) + return true; + } + return false; +} +function addDenseCandidate(candidates, index) { + if (candidates.bits !== void 0) { + candidates.bits[index] = 1; + return; + } + candidates.indices.push(index); + if (candidates.indices.length < 256) + return; + candidates.bits = new Uint8Array(candidates.length); + for (const existing of candidates.indices) + candidates.bits[existing] = 1; + candidates.indices.length = 0; +} +function recordDenseArrayPosition(node, groups) { + if (!locateDenseArrayPosition(node)) + return; + let candidates = groups.get(locatedDenseArray); + if (candidates === void 0) { + candidates = { indices: [], bits: void 0, length: nodeBase(locatedDenseArray).length }; + groups.set(locatedDenseArray, candidates); + } + addDenseCandidate(candidates, locatedDenseIndex); +} +function buildDenseRegions(candidates) { + if (candidates.bits === void 0) + return []; + const regions = []; + const bits = candidates.bits; + for (let at = 0; at < bits.length; ) { + while (at < bits.length && bits[at] === 0) + at += 1; + if (at === bits.length) + break; + const start = at; + let end = at; + let count = 0; + let gap = 0; + while (at < bits.length) { + if (bits[at] !== 0) { + count += 1; + end = at; + gap = 0; + } else if (++gap > 1) + break; + at += 1; + } + const length = end - start + 1; + if (count >= 256 && count * 2 >= length) + regions.push({ start, length }); + } + return regions; +} +function regionContaining(regions, index) { + for (const region of regions) + if (index >= region.start && index < region.start + region.length) + return true; + return false; +} +function hasReservedMutation(node) { + if (node.writeKey !== void 0 && RESERVED_SEGMENTS.has(node.writeKey)) + return true; + if (node.deleteKey !== void 0 && RESERVED_SEGMENTS.has(node.deleteKey)) + return true; + if (node.writes !== void 0) { + for (const key of node.writes.keys()) + if (RESERVED_SEGMENTS.has(key)) + return true; + } + if (node.deletes !== void 0) { + for (const key of node.deletes) + if (RESERVED_SEGMENTS.has(key)) + return true; + } + return false; +} +function hasFoldedAncestor(node, folded) { + for (let parent = nodeParent(node); parent !== void 0; parent = nodeParent(parent)) + if (folded.has(parent)) + return true; + return false; +} +function hasPlacementAncestor(node) { + for (let current = node; current !== void 0; current = nodeParent(current)) { + if (nodeParent(current) !== void 0 && current.parentPlacement) + return true; + } + return false; +} +function emitObjectWrite(node, path, operations, key, value2) { + const nextPath = [...path, key]; + const appended = node.appends?.get(key); + if (appended !== void 0) { + operations.push(["a", nextPath, appended]); + return false; + } + const before = node.readded?.has(key) || !Object.hasOwn(nodeBase(node), key) ? void 0 : nodeBase(node)[key]; + const after = cloneStored(value2, node.context); + const emitted = emitChangedValue(operations, nextPath, before, after); + return isContainer2(before) && isContainer2(after) && !emitted; +} +function emitObjectOperations(node, path, operations) { + if (node.readded !== void 0) { + for (const key of node.readded) { + if (Object.hasOwn(nodeBase(node), key)) + operations.push(["d", [...path, key]]); + } + } + let normalizedContainerWrite = false; + if (node.writeKey !== void 0) + normalizedContainerWrite = emitObjectWrite(node, path, operations, node.writeKey, objectValue(node, node.writeKey)); + if (node.writes !== void 0) { + for (const [key, valueIndex] of node.writes) { + if (operations.length > MAX_DELTA_OPERATIONS) + return normalizedContainerWrite; + if (emitObjectWrite(node, path, operations, key, storedValue(node.context, valueIndex))) + normalizedContainerWrite = true; + } + } + if (node.deleteKey !== void 0 && Object.hasOwn(nodeBase(node), node.deleteKey)) { + operations.push(["d", [...path, node.deleteKey]]); + } + if (node.deletes !== void 0) { + for (const key of node.deletes) { + if (operations.length > MAX_DELTA_OPERATIONS) + return normalizedContainerWrite; + if (Object.hasOwn(nodeBase(node), key)) + operations.push(["d", [...path, key]]); + } + } + return normalizedContainerWrite; +} +function buildArrayPlan(node) { + const overlay = arrayOverlay(node); + if (overlay.plan !== void 0) + return overlay.plan; + const base = nodeBase(node); + const pieces = piecesOf(overlay); + overlay.plan = orderedArrayPlan(base.length, pieces) ?? elementArrayPlan(base.length, pieces); + return overlay.plan; +} +function orderedArrayPlan(baseLength, pieces) { + const ranges = []; + for (const piece of pieces) { + if (piece.kind !== "base" || piece.length === 0) + continue; + if (piece.step !== 1 && piece.length > 1) + return void 0; + if (ranges.length > 0 && piece.start <= ranges[ranges.length - 1]) + return void 0; + ranges.push(piece.start, piece.start + piece.length - 1); + } + const removeRuns = []; + let end = baseLength; + for (let index = ranges.length - 2; index >= -2; index -= 2) { + const start = index >= 0 ? ranges[index + 1] + 1 : 0; + if (end > start) + removeRuns.push(start, end - start); + if (index >= 0) + end = ranges[index]; + } + return { removeRuns, permutation: void 0, insertRuns: insertRunsOf(pieces) }; +} +function elementArrayPlan(baseLength, pieces) { + const retained = new Uint8Array(baseLength); + const targetBase = []; + for (const piece of pieces) { + if (piece.kind !== "base") + continue; + for (let offset = 0; offset < piece.length; offset++) { + const index = piece.start + piece.step * offset; + retained[index] = 1; + targetBase.push(index); + } + } + const removeRuns = []; + for (let end = baseLength; end > 0; ) { + if (retained[end - 1] !== 0) { + end -= 1; + continue; + } + let start = end - 1; + while (start > 0 && retained[start - 1] === 0) + start -= 1; + removeRuns.push(start, end - start); + end = start; + } + const retainedBase = []; + for (let index = 0; index < retained.length; index++) + if (retained[index] !== 0) + retainedBase.push(index); + let permutation; + if (targetBase.some((value2, index) => value2 !== retainedBase[index])) { + const positions = new Map(retainedBase.map((value2, index) => [value2, index])); + permutation = targetBase.map((value2) => positions.get(value2)); + } + return { removeRuns, permutation, insertRuns: insertRunsOf(pieces) }; +} +function insertRunsOf(pieces) { + const insertRuns = []; + let logicalIndex = 0; + for (let pieceIndex = 0; pieceIndex < pieces.length; ) { + const piece = pieces[pieceIndex]; + if (piece.kind === "base") { + logicalIndex += piece.length; + pieceIndex += 1; + continue; + } + const startPiece = pieceIndex; + while (pieceIndex < pieces.length && pieces[pieceIndex].kind === "insert") { + logicalIndex += pieces[pieceIndex].length; + pieceIndex += 1; + } + insertRuns.push(logicalIndex - rangeLength(pieces, startPiece, pieceIndex), startPiece, pieceIndex); + } + return insertRuns; +} +function rangeLength(pieces, start, end) { + let length = 0; + for (let index = start; index < end; index++) + length += pieces[index].length; + return length; +} +function emitArrayOperations(node, path, operations, denseRegions) { + const overlay = arrayOverlay(node); + const base = nodeBase(node); + if (denseRegions !== void 0) { + for (const region of denseRegions) { + if (operations.length > MAX_DELTA_OPERATIONS) + return; + operations.push(["p", path, region.start, region.length, cloneArrayRegion(node, region)]); + } + } + if (overlay.structural) { + const plan = buildArrayPlan(node); + for (let index = 0; index < plan.removeRuns.length; index += 2) { + if (operations.length > MAX_DELTA_OPERATIONS) + return; + operations.push(["p", path, plan.removeRuns[index], plan.removeRuns[index + 1], []]); + } + if (plan.permutation !== void 0) + operations.push(["m", path, plan.permutation]); + const pieces = piecesOf(overlay); + for (let run2 = 0; run2 < plan.insertRuns.length; run2 += 3) { + if (operations.length > MAX_DELTA_OPERATIONS) + return; + const logicalIndex = plan.insertRuns[run2]; + const items = []; + for (let pieceIndex = plan.insertRuns[run2 + 1]; pieceIndex < plan.insertRuns[run2 + 2]; pieceIndex++) { + const piece = pieces[pieceIndex]; + for (let offset = 0; offset < piece.length; offset++) { + const sourceIndex = piece.start + piece.step * offset; + items.push(cloneStored(entryValueAt(node, piece, sourceIndex), node.context)); + } + } + operations.push(["p", path, logicalIndex, 0, items]); + } + } + for (const [baseIndex, valueIndex] of overlay.baseOverrides ?? []) { + if (operations.length > MAX_DELTA_OPERATIONS) + return; + const index = findEntryIndex(overlay, 1, baseIndex, void 0); + if (index === void 0 || denseRegions !== void 0 && regionContaining(denseRegions, index)) + continue; + emitChangedValue(operations, [...path, index], base[baseIndex], cloneStored(storedValue(node.context, valueIndex), node.context)); + } +} +function cloneArrayRegion(node, region) { + const overlay = arrayOverlay(node); + const result = []; + for (let index = region.start; index < region.start + region.length; index++) { + const piece = locatePiece(overlay, index); + const sourceIndex = piece.start + piece.step * overlay.locatedOffset; + result.push(cloneStored(entryValueAt(node, piece, sourceIndex), node.context)); + } + return result; +} +function emitChangedValue(operations, path, before, after) { + if (!isContainer2(after) && before === after) + return false; + if (isContainer2(before) && isContainer2(after) && equalTrustedJson(before, after)) + return false; + if (typeof before === "string" && typeof after === "string") { + if (after.length > before.length && after.slice(0, before.length) === before) { + operations.push(["a", path, ownedSlice2(after, before.length)]); + return true; + } + const shared = overlap(before, after, 65536); + if (shared > 0) { + operations.push(["t", path, before.length - shared]); + if (after.length > shared) + operations.push(["a", path, ownedSlice2(after, shared)]); + return true; + } + } + operations.push(["s", path, after]); + return true; +} +function emitSet(operations, path, value2) { + if (path.length === 0) + operations.push(["r", value2]); + else + operations.push(["s", path, value2]); +} +function resolvePath(node) { + if (node.preparedPath !== void 0) + return node.preparedPath; + const parent = nodeParent(node); + if (parent === void 0) { + node.preparedPath = []; + return node.preparedPath; + } + const parentPath = resolvePath(parent); + if (parentPath === void 0) + return void 0; + if (node.parentKind === 0) { + const key = node.parentKey; + if (!objectHas(parent, key) || objectValue(parent, key) !== nodeBase(node)) + return void 0; + node.preparedPath = [...parentPath, key]; + return node.preparedPath; + } + const overlay = arrayOverlay(parent); + const index = findEntryIndex(overlay, node.parentKind, node.parentKey, node.parentSource); + if (index === void 0) + return void 0; + const piece = locatePiece(overlay, index); + if (entryValueAt(parent, piece, node.parentKey) !== nodeBase(node)) + return void 0; + node.preparedPath = [...parentPath, index]; + return node.preparedPath; +} +function ensurePieceLocations(overlay) { + if (overlay.baseLocations !== void 0) + return; + overlay.baseLocations = []; + overlay.insertLocations = /* @__PURE__ */ new Map(); + let logicalStart = 0; + for (const piece of piecesOf(overlay)) { + const last = piece.start + piece.step * (piece.length - 1); + const location = { + piece, + logicalStart, + minimum: Math.min(piece.start, last), + maximum: Math.max(piece.start, last) + }; + if (piece.kind === "base") + overlay.baseLocations.push(location); + else { + let locations = overlay.insertLocations.get(piece.source); + if (locations === void 0) { + locations = []; + overlay.insertLocations.set(piece.source, locations); + } + locations.push(location); + } + logicalStart += piece.length; + } + const byMinimum = (left, right) => left.minimum - right.minimum; + overlay.baseLocations.sort(byMinimum); + for (const locations of overlay.insertLocations.values()) + locations.sort(byMinimum); +} +function findEntryIndex(overlay, kind, sourceIndex, source) { + if (kind === 1 && !overlay.structural) + return sourceIndex; + ensurePieceLocations(overlay); + const locations = kind === 1 ? overlay.baseLocations : overlay.insertLocations.get(source); + if (locations === void 0) + return void 0; + let low = 0; + let high = locations.length; + while (low < high) { + const middle = low + high >>> 1; + if (locations[middle].minimum <= sourceIndex) + low = middle + 1; + else + high = middle; + } + const location = locations[low - 1]; + if (location === void 0 || sourceIndex > location.maximum) + return void 0; + const offset = (sourceIndex - location.piece.start) / location.piece.step; + return offset >= 0 && offset < location.piece.length ? location.logicalStart + offset : void 0; +} +function ensureOperations(context) { + if (context.ops !== void 0) + return context.ops; + assertReadable(context); + if (context.replacement) { + const base = context.tracker.deref()?.replacementBase(context); + context.replacementNoop = base !== void 0 && equalTrustedJson(base, nodeBase(context.root)); + context.ops = context.replacementNoop ? [] : [["r", nodeBase(context.root)]]; + } else + context.ops = emitOperations(context); + return context.ops; +} +function equalTrustedJson(left, right) { + if (left === right) + return true; + if (!isContainer2(left) || !isContainer2(right) || Array.isArray(left) !== Array.isArray(right)) + return false; + if (Array.isArray(left)) { + const other2 = right; + if (left.length !== other2.length) + return false; + for (let index = 0; index < left.length; index++) + if (!equalTrustedJson(left[index], other2[index])) + return false; + return true; + } + const other = right; + const keys = Object.keys(left); + if (keys.length !== Object.keys(other).length) + return false; + for (const key of keys) + if (!Object.hasOwn(other, key) || !equalTrustedJson(left[key], other[key])) + return false; + return true; +} +function abortContext(context) { + if (context.status.value === "aborted" || context.status.value === "consumed" || context.status.value === "stale") + return; + context.status.value = "aborted"; + clearContext(context); +} +function releaseOverlayReferences(context) { + context.tracker.deref()?.releaseContext(context); + if (locatedDenseArray?.context === context) + locatedDenseArray = void 0; + context.overlayReleased = true; + context.dirty.length = 0; + context.nodes.length = 0; + context.rawNodes = void 0; + context.ops = void 0; + context.root = void 0; + context.bases = void 0; + context.stored = void 0; + context.baseValue = void 0; +} +function clearContext(context) { + context.tracker.deref()?.releaseContext(context); + if (locatedDenseArray?.context === context) + locatedDenseArray = void 0; + for (const node of context.nodes) { + if (Array.isArray(node.target)) + node.target.length = 0; + Reflect.deleteProperty(node.target, NODE); + node.writes?.clear(); + node.deletes?.clear(); + node.readded?.clear(); + if (node.array?.pieces !== void 0) + node.array.pieces.length = 0; + if (node.array !== void 0) { + node.array.root = void 0; + node.array.baseLocations = void 0; + node.array.insertLocations = void 0; + } + node.array?.baseOverrides?.clear(); + node.array?.insertOverrides?.clear(); + node.parentSource = void 0; + node.target = RELEASED; + node.proxy = RELEASED; + node.writeKey = void 0; + node.writeValue = void 0; + node.writes = void 0; + node.deleteKey = void 0; + node.deletes = void 0; + node.readded = void 0; + node.array = void 0; + node.subtreeDirty = void 0; + node.preparedPath = void 0; + } + context.dirty.length = 0; + context.nodes.length = 0; + context.rawNodes = void 0; + context.ops = void 0; + context.root = void 0; + context.bases = void 0; + context.stored = void 0; + context.baseValue = void 0; + context.overlayReleased = true; +} +function isContainer2(value2) { + return value2 !== null && typeof value2 === "object"; +} + +// node_modules/@earendil-works/chord/dist/delta/pending.js +var MAX_PENDING_OPS = 1e4; +var EMPTY = { kind: "empty" }; +var REPLACE = { kind: "replace" }; +var NO_OPS = { kind: "ops", ops: [] }; +var REPLACE_TAKE = { kind: "replace" }; +var PendingOps = class { + #state = EMPTY; + /** Queue the ops of one commit. */ + push(ops) { + if (ops.length === 0) + return; + const state = this.#state; + if (ops[0][0] === "r") { + this.#state = { kind: "batch", ops }; + return; + } + switch (state.kind) { + case "empty": + this.#state = { kind: "batch", ops }; + return; + case "batch": { + const folding = { kind: "folding", ops: [], leaves: /* @__PURE__ */ new Map() }; + this.#state = folding; + if (this.#fold(state.ops, folding)) + this.#fold(ops, folding); + return; + } + case "folding": + this.#fold(ops, state); + return; + case "replace": + return; + } + } + /** + * Pending ops after folding; 1 once overflowed (the replacement the owner sends). One batch is counted as received, + * so a single commit larger than `MAX_PENDING_OPS` counts in full until a second one arrives and overflows. + */ + get size() { + const state = this.#state; + if (state.kind === "empty") + return 0; + return state.kind === "replace" ? 1 : state.ops.length; + } + /** Hand over everything pending and start empty. */ + take() { + const state = this.#state; + this.#state = EMPTY; + switch (state.kind) { + case "empty": + return NO_OPS; + case "batch": + case "folding": + return { kind: "ops", ops: state.ops }; + case "replace": + return REPLACE_TAKE; + } + } + /** Fold `ops` into `folding`; false once the queue overflowed into `replace`. */ + #fold(ops, folding) { + for (const op2 of ops) { + switch (op2[0]) { + case "r": + folding.ops.length = 0; + folding.leaves.clear(); + break; + case "a": + if (mergeLeaf(op2, folding)) + continue; + break; + case "s": + if (isPrimitive(op2[2])) { + if (mergeLeaf(op2, folding)) + continue; + } else if (folding.leaves.size > 0) + folding.leaves.clear(); + break; + default: + if (folding.leaves.size > 0) + folding.leaves.clear(); + } + folding.ops.push(op2); + if (folding.ops.length > MAX_PENDING_OPS) { + this.#state = REPLACE; + return false; + } + } + return true; + } +}; +var isPrimitive = (value2) => value2 === null || typeof value2 !== "object"; +function mergeLeaf(op2, folding) { + const key = pathKey(op2[1]); + const at = folding.leaves.get(key); + if (at !== void 0) { + const merged = merge2(folding.ops[at], op2); + if (merged !== void 0) { + folding.ops[at] = merged; + return true; + } + } + folding.leaves.set(key, folding.ops.length); + return false; +} +function pathKey(path) { + return JSON.stringify(path); +} +function merge2(previous, next) { + if (next[0] === "s") + return next; + if (previous[0] === "a") + return ["a", previous[1], previous[2] + next[2]]; + if (typeof previous[2] === "string") + return ["s", previous[1], previous[2] + next[2]]; + return void 0; +} + +// node_modules/@earendil-works/chord/dist/delta/index.js +var isObj = (value2) => value2 !== null && typeof value2 === "object"; +function overlap(a, b, scan, probe = 64, maxCandidates = 8) { + if (a.length === 0 || b.length === 0 || scan === 0) + return 0; + const tail = a.length > scan ? a.slice(a.length - scan) : a; + for (const h of [Math.min(probe, b.length), 1]) { + const head = b.slice(0, h); + let tried = 0; + for (let k = tail.indexOf(head); k !== -1; k = tail.indexOf(head, k + 1)) { + if (++tried > maxCandidates) + break; + const n = tail.length - k; + if (n <= b.length && tail.slice(k) === b.slice(0, n)) + return n; + } + if (h === 1) + break; + } + return 0; +} +function ownedSlice2(text, start, end = text.length) { + return `${text.slice(start, end)} `.slice(0, -1); +} +var RESERVED_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]); +var UnsafePathError = class extends Error { + // Not a parameter property: Node's --experimental-strip-types rejects those, + // and these files are meant to run under it directly. + segment; + constructor(segment) { + super(`unsafe path segment: ${String(segment)}`); + this.segment = segment; + this.name = "UnsafePathError"; + } +}; +function assertValidOp(op2) { + if (!Array.isArray(op2) || op2.length === 0) + throw new TypeError("op is not a tuple"); + switch (op2[0]) { + case "r": + if (op2.length !== 2) + throw new TypeError("r arity"); + return; + case "s": + if (op2.length !== 3) + throw new TypeError("s arity"); + assertPathArg(op2[1], true); + return; + case "d": + if (op2.length !== 2) + throw new TypeError("d arity"); + assertPathArg(op2[1], true); + return; + case "a": + if (op2.length !== 3 || typeof op2[2] !== "string") + throw new TypeError("a shape"); + assertPathArg(op2[1], true); + return; + case "t": + if (op2.length !== 3 || !Number.isInteger(op2[2]) || op2[2] < 0) + throw new TypeError("t shape"); + assertPathArg(op2[1], true); + return; + case "p": { + if (op2.length !== 5) + throw new TypeError("p arity"); + assertPathArg(op2[1]); + if (!Number.isInteger(op2[2]) || op2[2] < 0) + throw new TypeError("p index"); + if (!Number.isInteger(op2[3]) || op2[3] < 0) + throw new TypeError("p remove"); + if (!Array.isArray(op2[4])) + throw new TypeError("p items"); + return; + } + case "m": + if (op2.length !== 3) + throw new TypeError("m arity"); + assertPathArg(op2[1]); + assertPermutation(op2[2]); + return; + // Silently skipping an unknown verb is how a newer producer's op vanishes. + default: + throw new TypeError(`unknown op verb: ${String(op2[0])}`); + } +} +function assertPathArg(p, nonEmpty = false) { + if (!Array.isArray(p)) + throw new TypeError("path is not an array"); + if (nonEmpty && p.length === 0) + throw new TypeError("path is empty"); + assertSafePath(p); +} +function assertPermutation(value2) { + if (!Array.isArray(value2)) + throw new TypeError("m permutation is not an array"); + const seen = new Uint8Array(value2.length); + for (const index of value2) { + if (!Number.isInteger(index) || index < 0 || index >= value2.length || seen[index] !== 0) { + throw new TypeError("m permutation is not a bijection"); + } + seen[index] = 1; + } +} +function assertSafePath(path) { + for (const seg of path) { + if (typeof seg === "string") { + if (RESERVED_SEGMENTS.has(seg)) + throw new UnsafePathError(seg); + } else if (!Number.isInteger(seg) || seg < 0) { + throw new UnsafePathError(seg); + } + } +} +function assertIndexInRange(parent, index) { + if (index > parent.length) + throw new UnsafePathError(index); +} +var PathError = class extends Error { + path; + constructor(path) { + super(`unresolvable path: ${JSON.stringify(path)}`); + this.path = path; + this.name = "PathError"; + } +}; +function apply(target, ops) { + return applyOps(target, ops); +} +function applyOps(target, ops) { + let root2 = target; + for (const op2 of ops) { + assertValidOp(op2); + if (op2[0] === "r") { + root2 = op2[1]; + continue; + } + const path = op2[1]; + assertSafePath(path); + if (op2[0] === "p") { + const target_ = path.length === 0 ? root2 : resolve(root2, path); + if (!Array.isArray(target_)) + throw new PathError(path); + target_.splice(op2[2], op2[3]); + const chunkSize = 1e4; + for (let offset = 0; offset < op2[4].length; offset += chunkSize) { + target_.splice(op2[2] + offset, 0, ...op2[4].slice(offset, offset + chunkSize)); + } + continue; + } + if (op2[0] === "m") { + const target_ = path.length === 0 ? root2 : resolve(root2, path); + if (!Array.isArray(target_) || target_.length !== op2[2].length) + throw new PathError(path); + const previous = target_.slice(); + for (let index = 0; index < op2[2].length; index++) + target_[index] = previous[op2[2][index]]; + continue; + } + const parent = resolve(root2, path.slice(0, -1)); + const key = path[path.length - 1]; + if (Array.isArray(parent)) { + if (typeof key !== "number") + throw new UnsafePathError(key); + assertIndexInRange(parent, key); + } + const write = (value2) => { + Object.defineProperty(parent, key, { value: value2, writable: true, enumerable: true, configurable: true }); + }; + const read2 = () => Object.hasOwn(parent, key) ? parent[key] : void 0; + switch (op2[0]) { + case "s": + write(op2[2]); + break; + case "d": + if (Array.isArray(parent)) { + if (typeof key !== "number" || key >= parent.length) + throw new PathError(path); + parent.splice(key, 1); + } else + delete parent[key]; + break; + case "a": { + const current = read2(); + if (typeof current !== "string") + throw new PathError(path); + write(`${current}${op2[2]}`); + break; + } + case "t": { + const current = read2(); + if (typeof current !== "string") + throw new PathError(path); + write(current.slice(op2[2])); + break; + } + } + } + return root2; +} +function applyImmutable(target, ops) { + return applyImmutableBatches(target, [ops]); +} +function applyImmutableBatches(target, batches) { + let root2 = target; + const owned = /* @__PURE__ */ new WeakSet(); + for (const ops of batches) { + for (const op2 of ops) { + assertValidOp(op2); + if (op2[0] === "r") { + root2 = op2[1]; + continue; + } + if (op2[0] === "p") { + const appended = appendCopy(root2, op2, owned); + if (appended !== void 0) { + root2 = appended; + continue; + } + } + root2 = copyContainers(root2, op2[0] === "p" || op2[0] === "m" ? op2[1] : op2[1].slice(0, -1), owned); + root2 = applyOps(root2, [op2]); + } + } + return root2; +} +function appendCopy(root2, op2, owned) { + const [, path, index, deleteCount, items] = op2; + if (deleteCount !== 0) + return void 0; + let target = root2; + for (const segment of path) { + const valid = typeof segment === "string" ? !RESERVED_SEGMENTS.has(segment) && isObj(target) && !Array.isArray(target) : Number.isInteger(segment) && segment >= 0 && Array.isArray(target); + if (!valid || !Object.hasOwn(target, segment)) + return void 0; + target = target[segment]; + } + if (!Array.isArray(target) || owned.has(target) || index !== target.length) + return void 0; + const appended = target.concat(items); + owned.add(appended); + if (path.length === 0) + return appended; + const parentPath = path.slice(0, -1); + const copiedRoot = copyContainers(root2, parentPath, owned); + Object.defineProperty(resolve(copiedRoot, parentPath), path[path.length - 1], { + value: appended, + writable: true, + enumerable: true, + configurable: true + }); + return copiedRoot; +} +function copyContainers(root2, path, owned) { + const copy2 = (value2) => { + if (Array.isArray(value2)) + return value2.slice(); + if (!isObj(value2)) + throw new PathError(path); + return Object.getPrototypeOf(value2) === null ? Object.assign(/* @__PURE__ */ Object.create(null), value2) : { ...value2 }; + }; + if (!isObj(root2)) + throw new PathError(path); + let copiedRoot; + if (owned.has(root2)) + copiedRoot = root2; + else { + copiedRoot = copy2(root2); + owned.add(copiedRoot); + } + let destination = copiedRoot; + for (const segment of path) { + if (!Object.hasOwn(destination, segment)) + throw new PathError(path); + if (Array.isArray(destination) && typeof segment !== "number") + throw new UnsafePathError(segment); + const child = destination[segment]; + if (!isObj(child)) + throw new PathError(path); + if (owned.has(child)) { + destination = child; + continue; + } + const copiedChild = copy2(child); + Object.defineProperty(destination, segment, { + value: copiedChild, + writable: true, + enumerable: true, + configurable: true + }); + owned.add(copiedChild); + destination = copiedChild; + } + return copiedRoot; +} +function resolveValue(root2, path) { + let node = root2; + for (const seg of path) { + if (!isObj(node)) + throw new PathError(path); + if (Array.isArray(node) && typeof seg !== "number") + throw new UnsafePathError(seg); + if (!Object.hasOwn(node, seg)) + throw new PathError(path); + node = node[seg]; + } + return node; +} +function resolve(root2, path) { + const node = resolveValue(root2, path); + if (!isObj(node)) + throw new PathError(path); + return node; +} + +// node_modules/@earendil-works/chord/dist/watch.js +var STOPPED = { kind: "stopped" }; +var ABORTED = { kind: "aborted" }; +var ENDED = { kind: "ended" }; +var WatchLifecycle = class { + #detach; + #report; + #closed = Promise.withResolvers(); + #value; + #listener; + #started = false; + #scheduled = false; + #running = false; + /** Set by `endAfterDelivery()`: the source sends nothing more; the watch ends `ended` once it delivered the rest. */ + #ending = false; + /** Set once, by `#terminate()`. */ + #end; + #abortSignal; + #abortListener; + constructor(value2, detach, report2) { + this.#value = value2; + this.#detach = detach; + this.#report = report2; + } + get value() { + return this.#value; + } + get closed() { + return this.#closed.promise; + } + start(listener) { + if (this.#started) + throw new Error("Watch is already started"); + if (this.#end !== void 0) + throw new Error("Watch is stopped"); + this.#started = true; + this.#listener = listener; + this.#schedule(); + } + stop() { + this.#terminate(STOPPED); + return this.#closed.promise; + } + /** End the watch `aborted` when `signal` aborts; installed once. */ + observeAbort(signal) { + if (this.#abortSignal !== void 0) + throw new Error("Watch abort is already installed"); + if (this.#end !== void 0) + return; + this.#abortSignal = signal; + this.#abortListener = () => this.abort(); + signal.addEventListener("abort", this.#abortListener, { once: true }); + if (signal.aborted) + this.abort(); + } + /** End the watch `aborted`: its acquisition context was aborted. */ + abort() { + this.#terminate(ABORTED); + } + /** + * End the watch with `end` at once, dropping what is pending: the source closed (`ended`), or failed for good + * (`failed`). A failure the source may recover from is a `failed` call instead (`fail()`). + */ + end(end) { + this.#terminate(end); + } + /** + * The source sends nothing more after its last frames, such as a retirement: take no more frames, deliver what is + * pending, then end `ended`, after the running call returns, if one runs. Until then the watch stays attached, so + * `end()`, `stop()`, an abort, and a throwing listener still end it first; a watch never started keeps what is + * pending until one of them or `start()`. + */ + endAfterDelivery() { + if (this.#end !== void 0 || this.#ending) + return; + this.#ending = true; + if (!this.#running && this.pendingContext === void 0) + this.#terminate(ENDED); + } + /** Whether the watch still takes frames: it has not ended, and its source has not ended. */ + get open() { + return this.#end === void 0 && !this.#ending; + } + /** Something became pending: deliver it once started, never inline. */ + pending() { + if (this.#started) + this.#schedule(); + } + #schedule() { + if (this.#scheduled || this.#running || this.#end !== void 0) + return; + this.#scheduled = true; + queueMicrotask(() => { + this.#scheduled = false; + void this.#drain(); + }); + } + /** + * Deliver until nothing is pending; what arrives during a call is taken after it returns. A watch whose source ended + * ends once it delivered the rest and its last call returned. + */ + async #drain() { + if (this.#running || this.#end !== void 0 || !this.#started) + return; + this.#running = true; + try { + while (this.#end === void 0) { + const listener = this.#listener; + if (listener === void 0) + break; + const frameContext = this.pendingContext; + if (frameContext === void 0) { + if (this.#ending) + this.#terminate(ENDED); + break; + } + const call = this.next(); + if (call.kind === "value") + this.#value = call.value; + try { + await listener(call, withoutAbortSignal(frameContext)); + } catch (error) { + if (this.#end === void 0) { + this.#report?.(error); + this.#terminate({ kind: "listener_error", error: toError(error) }); + } + break; + } + } + } finally { + this.#running = false; + } + } + /** + * End the watch, once: detach, drop what is pending and every reference into the source, and settle `closed`. A + * callback already running keeps running. + */ + #terminate(end) { + if (this.#end !== void 0) + return; + this.#end = end; + const detach = this.#detach; + this.#detach = void 0; + this.#report = void 0; + this.#listener = void 0; + this.release(); + if (this.#abortListener !== void 0) + this.#abortSignal?.removeEventListener("abort", this.#abortListener); + this.#abortSignal = void 0; + this.#abortListener = void 0; + detach?.(); + this.#closed.resolve(end); + } +}; +function toError(error) { + if (error instanceof Error) + return error; + try { + return new Error(String(error)); + } catch { + return new Error(Object.prototype.toString.call(error)); + } +} +var Watch = class extends WatchLifecycle { + #ops = new PendingOps(); + /** + * The source's call while it is the only frame pending: the call passes it on, with no allocation. A second frame + * drops it, so its ops stay only as long as `PendingOps` keeps them (folded, or dropped by an overflow). + */ + #lone; + /** The newest frame's value and context, while a call is pending; the context also marks that one is. */ + #newestValue; + #newestContext; + /** A pending frame was a retirement. */ + #retired = false; + /** The newest frame was a failure: the next call is this. */ + #failure; + /** A failure came after the last value call: the next value call replaces the root, and ops are not kept. */ + #replace = false; + /** + * Queue the frame `call`. A value's ops turn the previous value into it, and `retired` says the document the watch + * follows was retired, which the next value call reports however many frames it folds; a failure is `fail()`. + */ + advance(call, context) { + if (call.kind === "failed") { + this.#fail(call, context); + return; + } + if (!this.open) + return; + if (this.#replace) { + this.#failure = void 0; + } else { + this.#lone = this.#newestContext === void 0 ? call : void 0; + this.#ops.push(call.ops); + } + this.#newestValue = call.value; + this.#newestContext = context; + if (call.retired) + this.#retired = true; + this.pending(); + } + /** + * Queue a failure the source may recover from: the pending frames are dropped (`value` keeps the last delivered + * value), the listener gets `{ kind: "failed", error }`, and the next value arrives as `[["r", value]]`. + */ + fail(error, context) { + this.#fail({ kind: "failed", error }, context); + } + #fail(call, context) { + if (!this.open) + return; + this.#ops.take(); + this.#lone = void 0; + this.#newestValue = void 0; + this.#failure = call; + this.#newestContext = context; + this.#replace = true; + this.pending(); + } + get pendingContext() { + return this.#newestContext; + } + next() { + if (this.#replace) + return this.#nextAfterFailure(); + const lone = this.#lone; + const value2 = this.#newestValue; + const batch = this.#ops.take(); + const retired = this.#retired; + this.#lone = void 0; + this.#newestValue = void 0; + this.#newestContext = void 0; + this.#retired = false; + if (lone !== void 0) + return lone; + const ops = batch.kind === "ops" ? batch.ops : [["r", value2]]; + return { kind: "value", value: value2, ops, retired }; + } + /** The pending failure, or the value after one as a root replacement (no ops were kept since the failure). */ + #nextAfterFailure() { + const failure = this.#failure; + this.#newestContext = void 0; + if (failure !== void 0) { + this.#failure = void 0; + return failure; + } + const value2 = this.#newestValue; + const retired = this.#retired; + this.#newestValue = void 0; + this.#retired = false; + this.#replace = false; + return { kind: "value", value: value2, ops: [["r", value2]], retired }; + } + release() { + this.#ops.take(); + this.#lone = void 0; + this.#newestValue = void 0; + this.#newestContext = void 0; + this.#retired = false; + this.#failure = void 0; + this.#replace = false; + } +}; + +// node_modules/@earendil-works/pi-durable/dist/ids.js +function idFromNumber(value2) { + return value2; +} +function seqFromNumber(value2) { + return value2; +} + +// node_modules/@earendil-works/pi-durable/dist/documents.js +function defineDoc(definition) { + validateDefinition(definition); + return { definition }; +} +function defineDocFamily(definition) { + validateDefinition(definition); + return { definition }; +} +function validateDefinition(definition) { + if (!Number.isSafeInteger(definition.version) || definition.version < 1) { + throw new TypeError(`Document ${definition.kind} version must be a positive integer`); + } +} +function resolveAddress(definition, args) { + let index = 0; + let scope; + switch (definition.scope) { + case "session": + scope = { kind: "session" }; + break; + case "conversation": + scope = { kind: "conversation", conversationId: ownerId(args[index++], definition) }; + break; + case "task": + scope = { kind: "task", taskId: ownerId(args[index++], definition) }; + break; + } + const key = definition.family === true ? args[index++] : void 0; + const address = key === void 0 ? { kind: definition.kind, scope } : { kind: definition.kind, scope, key }; + return { address, id: addressId(address), nextArgument: index }; +} +function ownerId(value2, definition) { + if (typeof value2 !== "number" || !Number.isSafeInteger(value2)) { + throw new TypeError(`Document ${definition.kind} requires a ${definition.scope} ID`); + } + return idFromNumber(value2); +} +function addressId(address) { + const owner = address.scope.kind === "session" ? null : address.scope.kind === "conversation" ? address.scope.conversationId : address.scope.taskId; + return JSON.stringify([address.kind, address.scope.kind, owner, address.key ?? null]); +} +function documentCreate(definition, address, id) { + const key = address.key === void 0 ? {} : { key: address.key }; + switch (address.scope.kind) { + case "session": + return { id, kind: address.kind, ...key, scope: address.scope }; + case "task": + return { id, kind: address.kind, ...key, scope: address.scope }; + case "conversation": + return { + id, + kind: address.kind, + ...key, + scope: address.scope, + history: definition.history, + fork: definition.fork + }; + } +} +function checkRecordScope(definition, record) { + if (record.scope.kind !== definition.scope || record.scope.kind === "conversation" && (record.history !== definition.history || record.fork !== definition.fork)) { + throw new TypeError(`Document ${record.id} (${record.kind}) does not match the supplied definition semantics`); + } +} +function checkRecordVersion(definition, record, version) { + if (version > definition.version) { + throw new Error(`Document ${record.id} (${record.kind}) has newer version ${version} than ${definition.version}`); + } + if (version < definition.version && definition.migrate === void 0) { + throw new Error(`Document ${record.id} (${record.kind}) requires migration from version ${version}`); + } +} +function materializeDocument(definition, stored) { + return materializeDocumentValue(definition, stored.record, stored.version, stored.value); +} +function materializeDocumentValue(definition, record, version, value2) { + checkRecordScope(definition, record); + checkRecordVersion(definition, record, version); + if (version === definition.version) + return value2; + return copyJson(definition.migrate(value2, version)); +} + +// node_modules/@earendil-works/pi-durable/dist/entries.js +function defineEntry(kind) { + if (typeof kind !== "string" || kind.length === 0) + throw new TypeError("Entry kind must be a non-empty string"); + return { + kind, + is: (entry2) => entry2 !== void 0 && entry2.kind === kind + }; +} +var UserEntry = defineEntry("pi.user"); +var AssistantEntry = defineEntry("pi.assistant"); +var SystemEntry = defineEntry("pi.system"); +var ToolResultEntry = defineEntry("pi.tool-result"); +var ResetEntry = defineEntry("pi.reset"); +var CompactionEntry = defineEntry("pi.compaction"); + +// node_modules/@earendil-works/pi-durable/dist/errors.js +function errorMessage(error) { + if (error instanceof Error) + return error.message; + try { + return String(error); + } catch { + return Object.prototype.toString.call(error); + } +} +var ReadAfterWrite = class extends Error { + /** `operation` names the call, such as `Tx.task()`. */ + constructor(operation) { + super(`${operation} cannot read tables after the first table write`); + this.name = "ReadAfterWrite"; + } +}; +var StorageRequestError = class extends Error { + constructor(message) { + super(message); + this.name = "StorageRequestError"; + } +}; +var SessionFailed = class extends Error { + constructor(cause) { + super("Session failed after a storage error; close and reopen it", { cause }); + this.name = "SessionFailed"; + } +}; +var ReadOnlySession = class extends Error { + constructor(what) { + super(`Read-only Harness: ${what} refused`); + this.name = "ReadOnlySession"; + } +}; +var ConversationBusy = class extends Error { + conversationId; + constructor(conversationId) { + super(`Conversation ${conversationId} is busy`); + this.name = "ConversationBusy"; + this.conversationId = conversationId; + } +}; +var ConversationIdle = class extends Error { + conversationId; + constructor(conversationId) { + super(`Conversation ${conversationId} is idle`); + this.name = "ConversationIdle"; + this.conversationId = conversationId; + } +}; + +// node_modules/@earendil-works/pi-durable/dist/timers.js +var MAX_TIMER_DELAY = 2147483647; +var inWorkers = typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers"; +var nativeTimer = (callback, delayMs, options) => { + if (options.background && inWorkers) + return void 0; + const arm = (remaining) => { + const next = setTimeout(() => { + if (remaining > MAX_TIMER_DELAY) + handle = arm(remaining - MAX_TIMER_DELAY); + else + callback(); + }, Math.min(remaining, MAX_TIMER_DELAY)); + if (options.background) + next.unref?.(); + return next; + }; + let handle = arm(Math.max(0, delayMs)); + if (options.background && typeof handle.unref !== "function") { + clearTimeout(handle); + return void 0; + } + return () => clearTimeout(handle); +}; +function hostTimers(setTimer, report2) { + const arm = setTimer ?? nativeTimer; + let reported = false; + const fallBack = (error) => { + if (reported) + return; + reported = true; + report2(error); + }; + return { + foreground: (callback, delayMs) => { + try { + const disarm = arm(callback, delayMs, { background: false }); + if (disarm !== void 0) + return disarm; + fallBack(new Error("HarnessOptions.setTimer declined a timer that paces work; using setTimeout")); + } catch (error) { + fallBack(error); + } + return nativeTimer(callback, delayMs, { background: false }); + }, + background: (callback, delayMs) => { + try { + return arm(callback, delayMs, { background: true }); + } catch (error) { + report2(error); + return void 0; + } + } + }; +} + +// node_modules/@earendil-works/pi-durable/dist/session/cached-storage.js +var CachedStorage = class { + #storage; + #conversations = new Lru(4096); + /** Live (non-terminal) task records, until their task ends. */ + #liveTasks = /* @__PURE__ */ new Map(); + /** + * Tasks some task waits on, or waited on until its wait ended and it has not moved on since: how many such waits name + * each, and its ended record once it ended. + */ + #awaited = /* @__PURE__ */ new Map(); + /** Per task that waits, or left its wait and has not changed since: what it waited on, and whether it left. */ + #waits = /* @__PURE__ */ new Map(); + // Ended task records carry inputs and outcomes, such as a tool call's arguments, so fewer are kept. + #tasks = new Lru(256); + #submissions = new Lru(256); + /** Per record with a read in flight: the reads, and how many published commits wrote it since the first began. */ + #reads = /* @__PURE__ */ new Map(); + constructor(storage) { + this.#storage = storage; + } + /** The backend's own scope for a publication (`Storage.publishing`), when it has one. */ + get publishing() { + return scopeOf(this.#storage); + } + /** Pass the batches through; the Session applies each one with `published()` when it publishes it. */ + commit(batches, receive, context) { + return this.#storage.commit(batches, receive, context); + } + /** + * Apply a batch `commit()` stored, when the Session publishes it. Its records are frozen in place and kept as + * they are, no copies: the Session's components that follow the publication, such as the scheduler's live tasks, + * hold the same objects, so a live task's record is in memory once. + */ + published(writes) { + for (const write of writes) { + switch (write.type) { + case "conversation": + this.#wrote(write.value.id); + this.#conversations.set(write.value.id, freeze(write.value)); + break; + case "task": + this.#wrote(write.value.id); + this.#followWait(write.value); + this.#keepTask(freeze(write.value)); + break; + case "submission": + this.#wrote(write.value.id); + this.#submissions.set(write.value.id, freeze(write.value)); + break; + } + } + } + mintId() { + return this.#storage.mintId(); + } + conversation(id, context) { + const cached = this.#conversations.get(id); + if (cached !== void 0) + return Promise.resolve(cached); + return this.#keep(id, () => this.#storage.conversation(id, context), (record) => this.#conversations.set(id, record)); + } + scanConversations(query, limit, cursor, context) { + return this.#storage.scanConversations(query, limit, cursor, context); + } + entry(first, second, third) { + if (third === void 0) + return this.#storage.entry(first, second); + return this.#storage.entry(first, second, third); + } + findLatestHeadMarker(conversationId, atOrBeforeEntryId, context) { + return this.#storage.findLatestHeadMarker(conversationId, atOrBeforeEntryId, context); + } + scanEntries(query, limit, cursor, context) { + return this.#storage.scanEntries(query, limit, cursor, context); + } + task(id, context) { + const cached = this.#liveTasks.get(id) ?? this.#awaited.get(id)?.record ?? this.#tasks.get(id); + if (cached !== void 0) + return Promise.resolve(cached); + return this.#keep(id, () => this.#storage.task(id, context), (record) => this.#keepTask(record)); + } + scanTasks(query, limit, cursor, context) { + return this.#storage.scanTasks(query, limit, cursor, context); + } + /** Cached as written only: this process writes every submission it settles, and a read one is usually settled. */ + submission(id, context) { + const cached = this.#submissions.get(id); + return cached === void 0 ? this.#storage.submission(id, context) : Promise.resolve(cached); + } + scanSubmissions(query, limit, cursor, context) { + return this.#storage.scanSubmissions(query, limit, cursor, context); + } + submissionByRequest(conversationId, requestId, context) { + return this.#storage.submissionByRequest(conversationId, requestId, context); + } + findDocument(address, at, context) { + return this.#storage.findDocument(address, at, context); + } + document(id, at, context) { + return this.#storage.document(id, at, context); + } + scanDocuments(query, limit, cursor, context) { + return this.#storage.scanDocuments(query, limit, cursor, context); + } + close(context) { + return this.#storage.close(context); + } + /** Records kept per table, for tests that bound memory. */ + get sizes() { + return { + conversations: this.#conversations.size, + tasks: this.#tasks.size, + liveTasks: this.#liveTasks.size, + awaited: this.#awaited.size, + waits: this.#waits.size, + submissions: this.#submissions.size + }; + } + /** Keep a frozen task record: a live one until its task ends, an ended one in the bounded table. */ + #keepTask(record) { + if (record.state.status === "terminal") { + this.#liveTasks.delete(record.id); + const awaited = this.#awaited.get(record.id); + if (awaited !== void 0) + awaited.record = record; + else + this.#tasks.set(record.id, record); + return; + } + this.#tasks.delete(record.id); + this.#liveTasks.set(record.id, record); + } + /** + * Follow a task's waits from its written record: a wait holds the ended records of its `on` until the task, after + * leaving the wait, changes again (or ends), as the phase that resumes reads their outcomes before its next commit. + */ + #followWait(record) { + const wait = this.#waits.get(record.id); + if (record.state.status === "waiting") { + if (wait !== void 0) + this.#release(wait.on); + const on = record.state.on; + this.#waits.set(record.id, { on, left: false }); + for (const id of on) { + let awaited = this.#awaited.get(id); + if (awaited === void 0) { + const ended = this.#tasks.get(id); + this.#tasks.delete(id); + awaited = ended === void 0 ? { count: 0 } : { count: 0, record: ended }; + this.#awaited.set(id, awaited); + } + awaited.count++; + } + return; + } + if (wait === void 0) + return; + if (!wait.left && record.state.status !== "terminal") { + wait.left = true; + return; + } + this.#waits.delete(record.id); + this.#release(wait.on); + } + /** A wait on `on` is over: what no other wait names goes back to the bounded table. */ + #release(on) { + for (const id of on) { + const awaited = this.#awaited.get(id); + if (--awaited.count > 0) + continue; + this.#awaited.delete(id); + if (awaited.record !== void 0) + this.#tasks.set(id, awaited.record); + } + } + /** A published commit wrote record `id`: a read of it in flight may have missed that. */ + #wrote(id) { + const reads = this.#reads.get(id); + if (reads !== void 0) + reads.version++; + } + /** Resolve with a read's result, frozen; keep a found record unless a commit published since wrote it. */ + async #keep(id, read2, keep) { + let reads = this.#reads.get(id); + if (reads === void 0) { + reads = { count: 0, version: 0 }; + this.#reads.set(id, reads); + } + reads.count++; + const version = reads.version; + let value2; + try { + value2 = await read2(); + } finally { + if (--reads.count === 0) + this.#reads.delete(id); + } + if (value2 === void 0) + return void 0; + freeze(value2); + if (reads.version === version) + keep(value2); + return value2; + } + /** Records with a read in flight, for tests that bound memory. */ + get readsInFlight() { + return this.#reads.size; + } +}; +function scopeOf(storage) { + if (storage.publishing === void 0) + return void 0; + return (publish2, context) => storage.publishing(publish2, context); +} +var Lru = class { + #map = /* @__PURE__ */ new Map(); + #capacity; + constructor(capacity) { + this.#capacity = capacity; + } + get(key) { + const value2 = this.#map.get(key); + if (value2 === void 0) + return void 0; + this.#map.delete(key); + this.#map.set(key, value2); + return value2; + } + get size() { + return this.#map.size; + } + delete(key) { + this.#map.delete(key); + } + set(key, value2) { + this.#map.delete(key); + this.#map.set(key, value2); + if (this.#map.size > this.#capacity) + this.#map.delete(this.#map.keys().next().value); + } +}; +function freeze(value2) { + if (value2 === null || typeof value2 !== "object" || Object.isFrozen(value2)) + return value2; + for (const child of Object.values(value2)) + freeze(child); + return Object.freeze(value2); +} + +// node_modules/@earendil-works/pi-durable/dist/session/conversation-tails.js +var LATEST_CAPACITY = 4096; +var MARKER_CAPACITY = 256; +var ConversationTails = class { + /** Newest entry ID per conversation, `null` for none. */ + #latest = /* @__PURE__ */ new Map(); + /** Newest head marker per conversation, `null` for none. */ + #markers = /* @__PURE__ */ new Map(); + /** The newest entry ID visible from `conversationId`, read with `read` when not known. */ + async latest(conversationId, read2) { + const known = use(this.#latest, conversationId); + if (known !== void 0) + return known ?? void 0; + const latest = await read2(); + put(this.#latest, conversationId, latest ?? null, LATEST_CAPACITY); + return latest; + } + /** + * The newest visible head marker at or before `atOrBefore` (any when `undefined`), read with `read` when not known. + * The newest marker answers every cutoff at or after it, and no marker answers every cutoff. + */ + async marker(conversationId, atOrBefore, read2) { + const marker = use(this.#markers, conversationId); + if (marker === null) + return void 0; + if (marker !== void 0 && (atOrBefore === void 0 || atOrBefore >= marker.id)) + return marker; + const latest = this.#latest.get(conversationId); + const found = await read2(); + if (atOrBefore === void 0 || latest !== void 0 && (latest ?? 0) <= atOrBefore) { + put(this.#markers, conversationId, found === void 0 ? null : freeze2(found), MARKER_CAPACITY); + } + return found; + } + /** The newest entry ID of `conversationId` if known, without reading: `null` for none, `undefined` when unknown. */ + peek(conversationId) { + return this.#latest.get(conversationId); + } + /** At a commit's publication: apply a durable batch. */ + apply(writes) { + for (const write of writes) { + if (write.type === "conversation") { + if (write.value.parent !== void 0) + continue; + put(this.#latest, write.value.id, null, LATEST_CAPACITY); + put(this.#markers, write.value.id, null, MARKER_CAPACITY); + } else if (write.type === "entry") { + const entry2 = write.value; + put(this.#latest, entry2.conversationId, entry2.id, LATEST_CAPACITY); + if (entry2.head !== void 0) { + put(this.#markers, entry2.conversationId, freeze2(entry2), MARKER_CAPACITY); + } + } + } + } + /** How many conversations have their newest entry kept, for tests that bound memory. */ + get size() { + return this.#latest.size; + } + /** How many conversations have their newest head marker kept, for tests that bound memory. */ + get markers() { + return this.#markers.size; + } +}; +function use(map, key) { + const value2 = map.get(key); + if (value2 === void 0) + return void 0; + map.delete(key); + map.set(key, value2); + return value2; +} +function put(map, key, value2, capacity) { + map.delete(key); + map.set(key, value2); + if (map.size > capacity) + map.delete(map.keys().next().value); +} +function freeze2(value2) { + if (value2 === null || typeof value2 !== "object" || Object.isFrozen(value2)) + return value2; + for (const child of Object.values(value2)) + freeze2(child); + return Object.freeze(value2); +} + +// node_modules/@earendil-works/pi-durable/dist/session/keys.js +function taskKey(id) { + return `task:${id}`; +} +function conversationKey(id) { + return `conv:${id}`; +} +function entryKey(id) { + return `entry:${id}`; +} +function appendKey(id) { + return `entry-append:${id}`; +} +function submissionKey(id) { + return `sub:${id}`; +} +function requestKey(conversationId, requestId) { + return `req:${conversationId}:${requestId}`; +} +function documentKey(addressId2) { + return `doc:${addressId2}`; +} +function incarnationKey(id) { + return `docid:${id}`; +} +function scopeKey(scope) { + switch (scope.kind) { + case "session": + return "docscope:session"; + case "conversation": + return `docscope:c${scope.conversationId}`; + case "task": + return `docscope:t${scope.taskId}`; + } +} +function ownedKey(node) { + return `owned:${node}`; +} +var ROOTS_KEY = "roots"; +var INTENT_KEY = "intent"; +var ALL_KEYS = "*"; +function tableKeys(writes, keys) { + for (const write of writes) { + switch (write.type) { + case "conversation": + keys.push(conversationKey(write.value.id)); + break; + case "entry": + keys.push(entryKey(write.value.id), appendKey(write.value.conversationId)); + break; + case "task": + keys.push(taskKey(write.value.id)); + break; + case "submission": + keys.push(submissionKey(write.value.id)); + if (write.value.requestId !== void 0) { + keys.push(requestKey(write.value.conversationId, write.value.requestId)); + } + break; + } + } +} +var GatedStorage = class { + #storage; + #touch; + constructor(storage, touch) { + this.#storage = storage; + this.#touch = touch; + } + commit(batches, receive, context) { + return this.#storage.commit(batches, receive, context); + } + mintId() { + return this.#storage.mintId(); + } + conversation(id, context) { + return this.#after(conversationKey(id), () => this.#storage.conversation(id, context)); + } + scanConversations(query, limit, cursor, context) { + return this.#after(ALL_KEYS, () => this.#storage.scanConversations(query, limit, cursor, context)); + } + entry(first, second, third) { + if (third === void 0) { + const id2 = first; + return this.#after(entryKey(id2), () => this.#storage.entry(id2, second)); + } + const conversationId = first; + const id = second; + return this.#after(conversationKey(conversationId), () => this.#after(entryKey(id), () => this.#storage.entry(conversationId, id, third))); + } + findLatestHeadMarker(conversationId, atOrBeforeEntryId, context) { + return this.#afterEntries(conversationId, () => this.#storage.findLatestHeadMarker(conversationId, atOrBeforeEntryId, context)); + } + scanEntries(query, limit, cursor, context) { + return this.#afterEntries(query.conversationId, () => this.#storage.scanEntries(query, limit, cursor, context)); + } + task(id, context) { + return this.#after(taskKey(id), () => this.#storage.task(id, context)); + } + scanTasks(query, limit, cursor, context) { + return this.#after(ALL_KEYS, () => this.#storage.scanTasks(query, limit, cursor, context)); + } + submission(id, context) { + return this.#after(submissionKey(id), () => this.#storage.submission(id, context)); + } + scanSubmissions(query, limit, cursor, context) { + return this.#after(ALL_KEYS, () => this.#storage.scanSubmissions(query, limit, cursor, context)); + } + submissionByRequest(conversationId, requestId, context) { + return this.#after(requestKey(conversationId, requestId), () => this.#storage.submissionByRequest(conversationId, requestId, context)); + } + findDocument(address, at, context) { + return this.#after(documentKey(addressId(address)), () => this.#storage.findDocument(address, at, context)); + } + document(id, at, context) { + return this.#after(incarnationKey(id), () => this.#storage.document(id, at, context)); + } + scanDocuments(query, limit, cursor, context) { + return this.#after(scopeKey(query.scope), () => this.#storage.scanDocuments(query, limit, cursor, context)); + } + close(context) { + return this.#storage.close(context); + } + /** + * Run a read of a conversation's entries once neither its appends nor its creation has an unpublished writer: Storage + * refuses the read of a conversation it does not have yet. + */ + #afterEntries(conversationId, read2) { + return this.#after(conversationKey(conversationId), () => this.#after(appendKey(conversationId), read2)); + } + /** Run `read` once `key` has no unpublished writer. */ + #after(key, read2) { + const gate = this.#touch(key); + return gate === void 0 ? read2() : gate.then(read2); + } +}; + +// node_modules/@earendil-works/pi-durable/dist/types.js +var ROOT_CONVERSATION_ID = 1; + +// node_modules/@earendil-works/pi-durable/dist/session/forks.js +var SCAN_PAGE_SIZE = 256; +async function prepareForkDocumentCopies(storage, parentConversationId, at, childConversationId, context) { + const entry2 = await storage.entry(parentConversationId, at, context); + if (entry2 === void 0) + throw new Error(`Entry ${at} is not visible from conversation ${parentConversationId}`); + const copies = []; + const copiedAddresses = /* @__PURE__ */ new Set(); + await collectCopies(storage, { kind: "conversation", conversationId: entry2.entry.conversationId }, entry2.commitSeq, "asOf", childConversationId, copies, copiedAddresses, context); + await collectCopies(storage, { kind: "conversation", conversationId: parentConversationId }, "current", "current", childConversationId, copies, copiedAddresses, context); + return copies; +} +async function collectCopies(storage, scope, at, policy, childConversationId, copies, copiedAddresses, context) { + let cursor; + do { + const page2 = await storage.scanDocuments({ scope, at }, SCAN_PAGE_SIZE, cursor, context); + for (const source of page2.items) { + if (source.scope.kind !== "conversation" || source.fork !== policy) + continue; + const id = await storage.mintId(); + const identity = { + id, + kind: source.kind, + ...source.key === void 0 ? {} : { key: source.key }, + scope: { kind: "conversation", conversationId: childConversationId } + }; + const record = source.history === "latest" ? { ...identity, history: "latest", fork: source.fork } : { ...identity, history: "rewindable", fork: source.fork }; + const copyAddress = addressId(record); + if (copiedAddresses.has(copyAddress)) { + const member = record.key === void 0 ? record.kind : `${record.kind}/${record.key}`; + throw new Error(`Fork selects multiple source documents for ${member}`); + } + copiedAddresses.add(copyAddress); + copies.push({ record, source: { id: source.id, at } }); + } + cursor = page2.next; + } while (cursor !== void 0); +} + +// node_modules/@earendil-works/pi-durable/dist/session/transaction.js +function applySubmissionChange(current, change) { + if (current.status === "done" || current.status === "unanswered") + return current; + if (change.status === "placed") { + if (current.status !== "queued") + throw new Error(`Submission ${current.id} is not queued`); + const status = current.type === "input" ? "placed" : "done"; + return { ...current, status, entry: change.entry }; + } + if (change.status === "done" && current.status !== "placed") { + throw new Error(`Submission ${current.id} is not a placed input or continue`); + } + return { ...current, ...change }; +} +var INTERNAL_SCAN_PAGE_SIZE = 256; +var EMPTY_OPERATIONS = []; +var TABLE_JSON_COPY_OPTIONS = { omitUndefinedProperties: true }; +var Transaction = class { + #host; + #context; + #scope; + #pendingOperations = /* @__PURE__ */ new Set(); + #sealed = false; + #hasTableWrite = false; + /** Atomic batch; conversation and entry writes stage eagerly, while task and document writes assemble later. */ + #writes = []; + #createdConversationIds = /* @__PURE__ */ new Set(); + #forkSourceConversationIds = /* @__PURE__ */ new Set(); + #forkSourceDocumentIds = /* @__PURE__ */ new Set(); + /** One entry per task touched by a public read, candidate write, or document-owner lookup. */ + #tasksById = /* @__PURE__ */ new Map(); + /** Submissions created by this transaction, by ID. */ + #submissions = /* @__PURE__ */ new Map(); + /** Submission settlements and placements in staging order; resolved against the latest candidate record during assembly. */ + #submissionChanges = []; + /** Write and publication plans of every staged incarnation, built during assembly. */ + #plans = []; + /** Every document acquisition or retirement marker in staging order. */ + #documents = []; + /** Latest transaction-local incarnation or retirement marker at each logical address. */ + #latestDocumentByAddress = /* @__PURE__ */ new Map(); + constructor(host, context, scope = {}) { + this.#host = host; + this.#context = context; + this.#scope = scope; + } + /** Internal: the context of the commit this transaction belongs to. */ + get context() { + return this.#context; + } + /** Internal: whether a table write was staged, after which table reads throw `ReadAfterWrite`. */ + get hasTableWrite() { + return this.#hasTableWrite; + } + /** + * Internal: whether `tx` is a transaction of a commit of the Session behind `host`. A brand check, so a proxy or + * another wrapper of a transaction is not one. + */ + static ownedBy(tx, host) { + return #host in tx && tx.#host === host; + } + // ─── Table reads ──────────────────────────────────────────────────────── + conversation(id) { + return this.#read("conversation", () => this.#host.storage.conversation(id, this.#context)); + } + entry(first, second) { + const kind = typeof first === "number" ? void 0 : first.kind; + const id = typeof first === "number" ? first : second; + return this.#read("entry", async () => { + const entry2 = (await this.#host.storage.entry(id, this.#context))?.entry; + return kind === void 0 || entry2?.kind === kind ? entry2 : void 0; + }); + } + task(id) { + return this.#read("task", () => this.#committedTask(id)); + } + scanConversations(query, limit, cursor) { + return this.#read("scanConversations", () => this.#host.storage.scanConversations(query, limit, cursor, this.#context)); + } + scanEntries(query, limit, cursor) { + return this.#read("scanEntries", () => this.#host.storage.scanEntries(query, limit, cursor, this.#context)); + } + latestHeadMarker(conversationId) { + return this.#read("latestHeadMarker", () => this.#host.latestHeadMarker(conversationId, this.#context)); + } + latestEntryId(conversationId) { + return this.#read("latestEntryId", () => this.#host.latestEntryId(conversationId, this.#context)); + } + scanTasks(query, limit, cursor) { + return this.#read("scanTasks", () => this.#host.storage.scanTasks(query, limit, cursor, this.#context)); + } + /** Internal: committed submission record. */ + submission(id) { + return this.#read("submission", () => this.#host.storage.submission(id, this.#context)); + } + /** Committed submission with a conversation-scoped request ID. */ + submissionByRequest(conversationId, requestId) { + return this.#read("submissionByRequest", () => this.#host.storage.submissionByRequest(conversationId, requestId, this.#context)); + } + // ─── Table writes ─────────────────────────────────────────────────────── + createConversation(options) { + return this.#write(() => this.#stageConversation(void 0, options.ownership)); + } + /** Internal final-form bootstrap path for the reserved root identity. */ + createRootConversation() { + return this.#write(() => this.#stageConversation(void 0, { kind: "ownerless" }, ROOT_CONVERSATION_ID)); + } + forkConversation(parentConversationId, at, options) { + return this.#write(() => this.#stageConversation({ conversationId: parentConversationId, at }, options.ownership)); + } + async #stageConversation(parent, ownership, reservedId) { + const ownerTaskId = ownership.kind === "task" ? ownership.taskId : void 0; + const id = reservedId ?? await this.#host.storage.mintId(); + this.#assertOpen(); + let owner; + if (ownerTaskId !== void 0) { + const task = await this.#currentTask(ownerTaskId); + this.#assertOpen(); + if (task === void 0) + throw new Error(`Conversation owner task ${ownerTaskId} does not exist`); + owner = { conversationId: task.conversationId, taskId: ownerTaskId }; + } + const record = { + id, + ...parent === void 0 ? {} : { parent }, + ...owner === void 0 ? {} : { owner } + }; + const copies = parent === void 0 ? [] : await prepareForkDocumentCopies(this.#host.storage, parent.conversationId, parent.at, id, this.#context); + this.#assertOpen(); + for (const copy2 of copies) { + this.#forkSourceDocumentIds.add(copy2.source.id); + const entry2 = { + addressId: addressId(copy2.record), + address: copy2.record, + target: { kind: "fork-copy", ...copy2 }, + retireOnCommit: false + }; + this.#documents.push(entry2); + this.#latestDocumentByAddress.set(entry2.addressId, entry2); + } + if (parent !== void 0) + this.#forkSourceConversationIds.add(parent.conversationId); + this.#createdConversationIds.add(id); + this.#writes.push({ type: "conversation", value: record }); + await this.#host.conversationCreated(this, record); + this.#assertOpen(); + return record; + } + appendEntry(first, second, third) { + if (typeof first === "number") + return this.#appendEntry(first, second); + return this.#appendEntry(second, { ...third, kind: first.kind }); + } + #appendEntry(conversationId, value2) { + return this.#write(async () => { + await this.#requireConversation(conversationId); + this.#assertOpen(); + const id = await this.#host.storage.mintId(); + this.#assertOpen(); + const { head, ...rest } = value2; + const record = copyJson({ + ...rest, + id, + conversationId, + head: head === "self" ? id : head, + byTaskId: this.#scope.taskId + }, TABLE_JSON_COPY_OPTIONS); + this.#writes.push({ type: "entry", value: record }); + return record; + }); + } + createTask(task, input, options) { + return this.#write(async () => { + if (options.submissionIds !== void 0) { + let trace; + let links; + for (let index = 0; index < options.submissionIds.length; index++) { + const id2 = options.submissionIds[index]; + const submission2 = this.#submissions.get(id2) ?? await this.#host.storage.submission(id2, this.#context); + if (index === 0) + trace = submission2?.trace ?? "root"; + else if (submission2?.trace !== void 0) { + links ??= []; + links.push(submission2.trace); + } + } + options = { ...options, trace, links }; + } + const ownership = options.ownership; + let owner; + if (ownership.kind === "task") { + owner = await this.#currentTask(ownership.taskId); + this.#assertOpen(); + if (owner === void 0) + throw new Error(`Task owner ${ownership.taskId} does not exist`); + if (options.background === true) + throw new TypeError("A child task cannot be background"); + if (options.conversationId !== void 0 && options.conversationId !== owner.conversationId) { + throw new Error(`A child task lives in its owner's conversation ${owner.conversationId}`); + } + } + const conversationId = owner?.conversationId ?? options.conversationId ?? this.#scope.conversationId; + if (conversationId === void 0) + throw new TypeError("Tx.createTask() requires options.conversationId"); + await this.#requireConversation(conversationId); + this.#assertOpen(); + const definition = task.definition; + const checkpoint = definition.initial(input); + const id = await this.#host.storage.mintId(); + this.#assertOpen(); + const record = copyJson({ + id, + conversationId, + kind: definition.name, + version: definition.version, + input, + trace: options.trace === "root" ? void 0 : options.trace ?? this.#context.telemetry.propagation?.inject(this.#context.telemetry), + links: options.links, + ...owner === void 0 ? {} : { owner: owner.id }, + background: options.background ?? false, + abortRequested: false, + ...options.abandonOnRestart === true ? { abandonOnRestart: true } : {}, + state: { status: "pending", checkpoint } + }, TABLE_JSON_COPY_OPTIONS); + this.#tasksById.set(id, { write: { kind: "create", record } }); + return id; + }); + } + /** Create a raw submission record with a fresh ID; no admission rules apply. */ + createSubmission(create) { + return this.#write(async () => { + await this.#requireConversation(create.conversationId); + this.#assertOpen(); + const id = await this.#host.storage.mintId(); + this.#assertOpen(); + const record = copyJson({ ...create, id }, TABLE_JSON_COPY_OPTIONS); + this.#submissions.set(id, record); + return record; + }); + } + /** + * Settle a submission. Resolved during assembly against the transaction's latest candidate record, falling back to + * committed state, so it is not a caller table read and works after the first table write. + */ + settleSubmission(id, settlement) { + this.#assertOpen(); + this.#hasTableWrite = true; + this.#submissionChanges.push({ id, change: copyJson(settlement) }); + } + /** Place a queued submission at `entry`; resolved during assembly like `settleSubmission()`. */ + placeSubmission(id, entry2) { + this.#assertOpen(); + this.#hasTableWrite = true; + this.#submissionChanges.push({ id, change: { status: "placed", entry: entry2 } }); + } + /** Internal: replace one task record completely. Tasks change their own state through their runtime. */ + setTask(value2) { + this.#assertOpen(); + this.#hasTableWrite = true; + const task = this.#taskEntry(value2.id); + const candidate = task.write?.record; + if (candidate?.state.status === "terminal") { + throw new Error(`Task ${value2.id} already has a terminal candidate`); + } + if (candidate !== void 0 && candidate.conversationId !== value2.conversationId) { + throw new Error(`Task ${value2.id} cannot change conversations`); + } + task.write = { + kind: task.write?.kind === "create" ? "create" : "replace", + record: copyJson(this.#stampTimes(value2, candidate), TABLE_JSON_COPY_OPTIONS) + }; + } + /** Internal: candidate records of the tasks this transaction created or replaced so far. */ + stagedTasks() { + const records = []; + for (const task of this.#tasksById.values()) + if (task.write !== void 0) + records.push(task.write.record); + return records; + } + /** Internal: IDs of the tasks this transaction creates. */ + createdTaskIds() { + const ids = []; + for (const [id, task] of this.#tasksById) + if (task.write?.kind === "create") + ids.push(id); + return ids; + } + /** Internal: conversations this transaction created or forked so far. */ + stagedConversations() { + const records = []; + for (const write of this.#writes) + if (write.type === "conversation") + records.push(write.value); + return records; + } + doc(token, ...args) { + try { + this.#assertOpen(); + const definition = token.definition; + const resolved = resolveAddress(definition, args); + this.#assertTaskDocumentsOpen(resolved); + const latest = this.#latestDocumentByAddress.get(resolved.id); + if (latest !== void 0 && !latest.retireOnCommit) { + if (latest.draftPromise !== void 0) + return latest.draftPromise; + if (latest.target?.kind === "fork-copy") { + latest.draftPromise = this.#track(this.#acquireForkCopy(latest, definition, latest.target)); + return latest.draftPromise; + } + } + const seed = definition.family === true ? copyJson(args[resolved.nextArgument]) : void 0; + const docEntry = { + addressId: resolved.id, + address: resolved.address, + definition, + retireOnCommit: false + }; + this.#documents.push(docEntry); + this.#latestDocumentByAddress.set(docEntry.addressId, docEntry); + docEntry.draftPromise = this.#track(this.#acquire(docEntry, seed, latest?.retireOnCommit === true)); + return docEntry.draftPromise; + } catch (error) { + return Promise.reject(error); + } + } + retireDoc(token, ...args) { + try { + this.#assertOpen(); + const definition = token.definition; + const resolved = resolveAddress(definition, args); + const latest = this.#latestDocumentByAddress.get(resolved.id); + if (latest?.retireOnCommit) + return Promise.resolve(); + if (latest?.target?.kind === "fork-copy") { + checkRecordScope(definition, latest.target.record); + latest.retireOnCommit = true; + return Promise.resolve(); + } + if (latest?.draftPromise !== void 0) { + latest.retireOnCommit = true; + return this.#track(latest.draftPromise.then(() => void 0)); + } + const entry2 = { + addressId: resolved.id, + address: resolved.address, + definition, + retireOnCommit: true + }; + this.#documents.push(entry2); + this.#latestDocumentByAddress.set(entry2.addressId, entry2); + return this.#track(this.#findRetirement(entry2)); + } catch (error) { + return Promise.reject(error); + } + } + async #acquire(entry2, seed, skipLoad) { + const definition = entry2.definition; + const loaded = skipLoad ? void 0 : await this.#host.load(definition, entry2.addressId, entry2.address, this.#context); + this.#assertOpen(); + if (loaded !== void 0) { + checkRecordScope(definition, loaded.record); + checkRecordVersion(definition, loaded.record, loaded.storedVersion); + entry2.target = { kind: "loaded", document: loaded }; + entry2.change = loaded.tracker.beginChange(); + return entry2.change.state; + } + const scope = entry2.address.scope; + if (scope.kind === "conversation") + await this.#requireConversation(scope.conversationId); + if (scope.kind === "task") { + const task = await this.#currentTask(scope.taskId); + if (task === void 0) + throw new Error(`Task ${scope.taskId} does not exist`); + if (task.state.status === "terminal") + throw new Error(`Task ${scope.taskId} is terminal`); + } + this.#assertOpen(); + const value2 = copyJson(definition.family === true ? definition.initial(seed) : definition.initial()); + const id = await this.#host.storage.mintId(); + this.#assertOpen(); + const tracker = track(value2); + entry2.target = { + kind: "created", + record: documentCreate(definition, entry2.address, id), + version: definition.version, + tracker + }; + entry2.change = tracker.beginChange(); + return entry2.change.state; + } + async #acquireForkCopy(entry2, definition, target) { + const stored = await this.#host.storage.document(target.source.id, target.source.at, this.#context); + this.#assertOpen(); + if (stored === void 0) { + throw new Error(`Fork source document ${target.source.id} cannot be read`); + } + if (stored.record.scope.kind !== "conversation" || stored.record.kind !== target.record.kind || stored.record.key !== target.record.key || stored.record.history !== target.record.history || stored.record.fork !== target.record.fork) { + throw new Error(`Fork source document ${target.source.id} does not match the copied record`); + } + const value2 = materializeDocumentValue(definition, target.record, stored.version, stored.value); + const tracker = track(value2); + entry2.definition = definition; + entry2.target = { kind: "created", record: target.record, version: definition.version, tracker }; + entry2.change = tracker.beginChange(); + return entry2.change.state; + } + async #findRetirement(entry2) { + const gate = this.#host.touch(documentKey(entry2.addressId)); + if (gate !== void 0) + await gate; + const record = this.#host.cached(entry2.addressId)?.record ?? await this.#host.storage.findDocument(entry2.address, "current", this.#context); + this.#assertOpen(); + if (record === void 0) + return; + checkRecordScope(entry2.definition, record); + entry2.target = { kind: "retire-only", record }; + } + // ─── Settlement ───────────────────────────────────────────────────────── + /** Seal after callback failure: abort every change and observe every pending operation. */ + async settleFailure() { + this.#sealed = true; + this.#abortChanges(); + await Promise.allSettled(this.#pendingOperations); + this.#context = BACKGROUND_CONTEXT; + } + /** + * Seal after callback success, prepare every open change, and assemble the atomic batch. + * Any failure aborts every change before Storage admission. + */ + async settleSuccess() { + this.#sealed = true; + if (this.#pendingOperations.size > 0) { + this.#abortChanges(); + await Promise.allSettled(this.#pendingOperations); + this.#context = BACKGROUND_CONTEXT; + throw new Error("Session commit callback settled before its pending Tx operations"); + } + try { + for (const document of this.#documents) { + if (document.change !== void 0) + document.prepared = document.change.prepare(); + } + return await this.#assemble(); + } catch (error) { + this.#abortChanges(); + throw error; + } finally { + this.#context = BACKGROUND_CONTEXT; + } + } + /** Abort every prepared change after Storage failure or when no write is required. */ + discard() { + this.#abortChanges(); + } + /** + * Internal: what a deferred commit holds in memory instead of storing (`CommitPersistence`), each changed incarnation + * with its operations and whether they selected a base; `undefined` when the commit must be stored. It may be held + * only when every write changes an existing `latest`, `initial`-fork conversation document at its stored version. + */ + holdable() { + if (this.#writes.some((write) => write.type !== "document.change")) + return void 0; + const held = []; + for (const plan of this.#plans) { + const { content, change } = plan; + if (content === void 0 && !plan.retire) + continue; + if (plan.retire || change?.loaded === void 0 || content?.type !== "document.change") + return void 0; + const { loaded, prepared, version } = change; + const record = loaded.record; + if (record.scope.kind !== "conversation" || record.history !== "latest" || record.fork !== "initial") { + return void 0; + } + if (loaded.storedVersion !== version) + return void 0; + held.push({ loaded, ops: prepared.ops, base: content.content.kind === "base" }); + } + return held; + } + /** + * Internal: adopt a held commit (`holdable()`) in memory only. Trackers advance by pointer swap; stored versions and + * delta counts stay, as nothing was stored. Returns its publication for the Session's own observers. + */ + adoptHeld() { + const publications = []; + for (const plan of this.#plans) { + const { tracker, prepared, version, loaded } = plan.change; + if (prepared.ops.length === 0) { + prepared.abort(); + continue; + } + tracker.adopt(prepared); + const record = loaded.record; + const conversationId = plan.conversationId; + publications.push({ + type: "document", + kind: "change", + record, + conversationId, + version, + value: prepared.value, + ops: prepared.ops + }); + } + return publications; + } + /** + * Internal: store the held changes of every incarnation this commit reads or writes in front of its own, so a stored + * document never misses an operation its later ones build on. Called right before Storage admission, after every + * fallible step, because it empties the holds: a failure earlier keeps them. Returns the holds it took. + */ + takeHeld(held) { + const taken = []; + for (const plan of this.#plans) { + if (!("createdAt" in plan.record)) + continue; + const hold = held(plan.record.id); + if (hold === void 0) + continue; + taken.push(hold); + const own = plan.content?.type === "document.change" ? plan.content : void 0; + const change = plan.change; + const value2 = change?.prepared.value ?? hold.loaded.tracker.value; + const stored = storeHeld(hold, change?.prepared.ops ?? EMPTY_OPERATIONS, value2, hold.loaded.valueVersion); + const content = own?.content.kind === "base" ? own.content : stored.content; + const write = { type: "document.change", id: plan.record.id, content }; + if (own !== void 0) + this.#writes[this.#writes.indexOf(own)] = write; + else + this.#insertBeforeRetirement(write); + if (!plan.retire) + plan.held = { ops: stored.ops, observed: own !== void 0 }; + plan.content = write; + if (plan.record.scope.kind === "conversation") + plan.conversationId = plan.record.scope.conversationId; + } + return taken; + } + /** + * Internal: the keys this commit writes, once settled (and after `takeHeld()`), for the Session's unpublished write + * set: its table records, and the address and incarnation of every document it creates, changes, or retires, with + * the scope of every incarnation it creates or retires. + */ + writeKeys() { + const keys = []; + tableKeys(this.#writes, keys); + for (const plan of this.#plans) { + if (plan.content === void 0 && !plan.retire) + continue; + keys.push(documentKey(plan.addressId), incarnationKey(plan.record.id)); + if (plan.retire || !("createdAt" in plan.record)) + keys.push(scopeKey(plan.record.scope)); + } + return keys; + } + /** Stage a content write for an incarnation, before its retirement when it retires. */ + #insertBeforeRetirement(write) { + const at = this.#writes.findIndex((candidate) => candidate.type === "document.retire" && candidate.id === write.id); + if (at < 0) + this.#writes.push(write); + else + this.#writes.splice(at, 0, write); + } + /** Adopt every prepared change by pointer swap after Storage success and describe the publication. */ + adopt(seq) { + const publications = []; + let stored; + for (const plan of this.#plans) { + const committed = "createdAt" in plan.record; + let record = committed ? plan.record : { ...plan.record, createdAt: seq }; + if (plan.retire) + record = { ...record, retiredAt: seq }; + const change = plan.change; + if (change !== void 0) { + const { tracker, prepared, loaded, version } = change; + if (loaded === void 0 ? !plan.retire : prepared.ops.length > 0) + tracker.adopt(prepared); + else + prepared.abort(); + if (loaded !== void 0) { + if (loaded.storedVersion < version) + loaded.storedVersion = version; + if (plan.content?.type === "document.change") { + if (plan.content.content.kind === "base") + loaded.deltasSinceBase = 0; + else + loaded.deltasSinceBase++; + } + } else if (!plan.retire) { + this.#host.install({ + addressId: plan.addressId, + record, + storedVersion: version, + valueVersion: version, + deltasSinceBase: 0, + tracker + }); + } + } + if (plan.retire && committed) + this.#host.evict(plan.addressId, record.id); + const publication = describe(plan, record); + if (publication === void 0) + continue; + const held = plan.held; + if (held === void 0) { + publications.push(publication); + stored?.push(publication); + continue; + } + stored ??= [...publications]; + if (held.observed) + publications.push(publication); + stored.push(publication.type === "document" && publication.kind === "change" ? { ...publication, ops: held.ops } : publication); + } + return { observed: publications, stored: stored ?? publications }; + } + async #assemble() { + const storage = this.#host.storage; + const plans = this.#plans; + for (const document of this.#documents) { + const plan = planDocument(document); + if (plan !== void 0) + plans.push(plan); + } + this.#rejectForkSourceWrites(plans); + await this.#validateOwners(); + for (const [id, task] of this.#tasksById) { + if (task.write?.kind !== "replace") + continue; + const committed = await this.#committedTask(id); + if (committed === void 0) + throw new Error(`Task ${id} does not exist`); + if (committed.state.status === "terminal") + throw new Error(`Task ${id} is already terminal`); + if (committed.conversationId !== task.write.record.conversationId) { + throw new Error(`Task ${id} cannot change conversations`); + } + } + const terminalTaskIds = /* @__PURE__ */ new Set(); + for (const task of this.#tasksById.values()) { + if (task.write?.record.state.status === "terminal") + terminalTaskIds.add(task.write.record.id); + } + if (terminalTaskIds.size > 0) { + const retiring = /* @__PURE__ */ new Set(); + for (const plan of plans) { + const scope = plan.record.scope; + if (scope.kind !== "task" || !terminalTaskIds.has(scope.taskId)) + continue; + plan.retire = true; + retiring.add(plan.record.id); + } + const retire = (record) => { + if (retiring.has(record.id)) + return; + plans.push({ addressId: addressId(record), record, retire: true }); + retiring.add(record.id); + }; + for (const taskId of terminalTaskIds) { + if (this.#tasksById.get(taskId)?.write?.kind === "create") + continue; + const gate = this.#host.touch(scopeKey({ kind: "task", taskId })); + if (gate !== void 0) + await gate; + const known = this.#host.taskDocuments(taskId); + if (known !== void 0) { + for (const record of known) + retire(record); + continue; + } + let cursor; + do { + const page2 = await storage.scanDocuments({ scope: { kind: "task", taskId }, at: "current" }, INTERNAL_SCAN_PAGE_SIZE, cursor, this.#context); + for (const record of page2.items) + retire(record); + cursor = page2.next; + } while (cursor !== void 0); + } + } + for (const plan of plans) { + if (!publishes(plan)) + continue; + const scope = plan.record.scope; + if (scope.kind === "conversation") + plan.conversationId = scope.conversationId; + if (scope.kind !== "task") + continue; + const task = this.#taskEntry(scope.taskId); + if (task.publicationConversationId === void 0) { + const current = await this.#currentTask(scope.taskId); + if (current !== void 0) + task.publicationConversationId = current.conversationId; + } + plan.conversationId = task.publicationConversationId; + } + for (const { id, change } of this.#submissionChanges) { + const current = this.#submissions.get(id) ?? await storage.submission(id, this.#context); + if (current === void 0) + throw new Error(`Submission ${id} does not exist`); + const next = applySubmissionChange(current, change); + if (next !== current) + this.#submissions.set(id, next); + } + const writes = this.#writes; + for (const value2 of this.#submissions.values()) + writes.push({ type: "submission", value: value2 }); + for (const task of this.#tasksById.values()) { + if (task.write !== void 0) + writes.push({ type: "task", value: task.write.record }); + } + for (const plan of plans) { + const change = plan.change; + if (plan.content?.type === "document.change" && plan.content.content.kind === "delta" && change?.loaded) { + const { prepared, version } = change; + const info = { deltasSinceBase: change.loaded.deltasSinceBase }; + if (change.definition.checkpointWhen(prepared.value, prepared.ops, info)) { + plan.content = { ...plan.content, content: { version, kind: "base", value: prepared.value } }; + } + } + if (plan.content !== void 0) + writes.push(plan.content); + if (plan.retire) + writes.push({ type: "document.retire", id: plan.record.id }); + } + return writes; + } + // ─── Helpers ──────────────────────────────────────────────────────────── + /** + * New owned work needs a live owner, judged on the owner's final candidate: not `completing`, terminal, or + * abort-marked. A task therefore cannot create owned work in the commit that finishes it (spec §5.5). + */ + async #validateOwners() { + const owners = []; + for (const write of this.#writes) { + if (write.type !== "conversation" || write.value.owner === void 0) + continue; + owners.push({ what: "Conversation owner task", taskId: write.value.owner.taskId }); + } + for (const task of this.#tasksById.values()) { + const record = task.write?.kind === "create" ? task.write.record : void 0; + if (record?.owner !== void 0) + owners.push({ what: "Task owner", taskId: record.owner }); + } + for (const { what, taskId } of owners) { + const task = await this.#currentTask(taskId); + if (task === void 0) + throw new Error(`${what} ${taskId} does not exist`); + if (task.state.status === "terminal" || task.state.status === "completing") { + throw new Error(`${what} ${taskId} is ${task.state.status}`); + } + if (task.abortRequested) + throw new Error(`${what} ${taskId} is abort-marked`); + } + } + #rejectForkSourceWrites(plans) { + for (const plan of plans) { + if (plan.content === void 0 && !plan.retire) + continue; + const record = plan.record; + if (this.#forkSourceDocumentIds.has(record.id)) { + throw new Error(`Cannot change fork source document ${record.id} in the fork transaction`); + } + const scope = plan.record.scope; + if (scope.kind === "conversation" && this.#forkSourceConversationIds.has(scope.conversationId) && record.scope.kind === "conversation" && record.fork === "current") { + throw new Error(`Cannot fork conversation ${scope.conversationId} while changing its current-policy documents`); + } + } + } + #abortChanges() { + for (const document of this.#documents) + document.change?.abort(); + } + #assertOpen() { + if (this.#sealed) + throw new Error("Transaction has settled"); + } + #assertTaskDocumentsOpen(resolved) { + const scope = resolved.address.scope; + if (scope.kind === "task" && this.#tasksById.get(scope.taskId)?.write?.record.state.status === "terminal") { + throw new Error(`Task ${scope.taskId} is terminal`); + } + } + /** Register an operation so callback settlement can reject and drain it. */ + #track(operation) { + this.#pendingOperations.add(operation); + const settle3 = () => { + this.#pendingOperations.delete(operation); + }; + operation.then(settle3, settle3); + return operation; + } + #read(method, read2) { + try { + this.#assertOpen(); + if (this.#hasTableWrite) + throw new ReadAfterWrite(`Tx.${method}()`); + return this.#track(read2()); + } catch (error) { + return Promise.reject(error); + } + } + #write(write) { + try { + this.#assertOpen(); + this.#hasTableWrite = true; + return this.#track(write()); + } catch (error) { + return Promise.reject(error); + } + } + async #requireConversation(id) { + if (this.#createdConversationIds.has(id)) + return; + if (await this.#host.storage.conversation(id, this.#context) === void 0) { + throw new Error(`Conversation ${id} does not exist`); + } + } + /** + * Lifecycle times: `startedAt` on the first change to `running`, `endedAt` on the change to `terminal`. Once set, + * they carry over from the replaced record; records written before they existed lack them. + */ + #stampTimes(value2, candidate) { + const status = value2.state.status; + const now = (stamps) => stamps ? this.#host.now() : void 0; + const startedAt = candidate?.startedAt ?? value2.startedAt ?? now(status === "running"); + const endedAt = candidate?.endedAt ?? value2.endedAt ?? now(status === "terminal"); + if (startedAt === value2.startedAt && endedAt === value2.endedAt) + return value2; + return { + ...value2, + ...startedAt === void 0 ? {} : { startedAt }, + ...endedAt === void 0 ? {} : { endedAt } + }; + } + #taskEntry(id) { + let task = this.#tasksById.get(id); + if (task === void 0) { + task = {}; + this.#tasksById.set(id, task); + } + return task; + } + /** Latest candidate task record, falling back to committed state; not a caller table read. */ + async #currentTask(id) { + return this.#tasksById.get(id)?.write?.record ?? await this.#committedTask(id); + } + #committedTask(id) { + const task = this.#taskEntry(id); + task.committedRead ??= this.#host.storage.task(id, this.#context); + return task.committedRead; + } +}; +function planDocument(document) { + const target = document.target; + if (target === void 0) + return void 0; + const plan = { addressId: document.addressId, retire: document.retireOnCommit }; + switch (target.kind) { + case "created": { + const prepared = document.prepared; + const { record, version, tracker } = target; + const content = { version, kind: "base", value: prepared.value }; + return { + ...plan, + record, + content: { type: "document.create", record, content }, + change: { tracker, prepared, version } + }; + } + case "fork-copy": + return { + ...plan, + record: target.record, + content: { type: "document.copy", record: target.record, source: target.source } + }; + case "retire-only": + return { ...plan, record: target.record }; + case "loaded": { + const loaded = target.document; + const definition = document.definition; + const prepared = document.prepared; + const version = definition.version; + const id = loaded.record.id; + const content = loaded.storedVersion < version ? { type: "document.change", id, content: { version, kind: "base", value: prepared.value } } : prepared.ops.length > 0 ? { type: "document.change", id, content: { version, kind: "delta", ops: prepared.ops } } : void 0; + const change = { + tracker: loaded.tracker, + prepared, + version, + loaded, + definition + }; + return { ...plan, record: loaded.record, change, ...content === void 0 ? {} : { content } }; + } + } +} +function describe(plan, record) { + const conversationId = plan.conversationId; + if (plan.retire) + return { type: "document", kind: "retire", record, conversationId }; + if (plan.content?.type === "document.copy") { + return { type: "document.copy", record, conversationId, source: plan.content.source }; + } + const change = plan.change; + if (change === void 0 || !publishes(plan)) + return void 0; + const ops = change.loaded === void 0 ? EMPTY_OPERATIONS : change.prepared.ops; + return { + type: "document", + kind: "change", + record, + conversationId, + version: change.version, + value: change.prepared.value, + ops + }; +} +function storeHeld(hold, ops, value2, version) { + hold.pending.push(ops); + const taken = hold.pending.take(); + if (taken.kind === "replace") + return { content: { version, kind: "base", value: value2 }, ops: [["r", value2]] }; + if (hold.base) + return { content: { version, kind: "base", value: value2 }, ops: taken.ops }; + return { content: { version, kind: "delta", ops: taken.ops }, ops: taken.ops }; +} +function publishes(plan) { + return plan.retire || plan.change?.loaded === void 0 || plan.content !== void 0; +} + +// node_modules/@earendil-works/pi-durable/dist/session/writer.js +var SESSION_FAILED = { kind: "failed" }; +var Writer = class { + #host; + /** Admitted parts not yet sent, in line order. */ + #queue = []; + #flight = false; + /** Per key, the newest unpublished part that writes it. */ + #unpublished = /* @__PURE__ */ new Map(); + /** The newest admitted part that is not yet published, whose gate opens after every earlier one's. */ + #newest; + constructor(host) { + this.#host = host; + } + /** Admit a part: register its keys, queue it, and send it at once unless a call is in flight. */ + admit(spec) { + const outcome = Promise.withResolvers(); + outcome.promise.catch(() => { + }); + const part = { + ...spec, + outcome: outcome.promise, + settle: { + resolve: () => { + part.done = true; + outcome.resolve(); + }, + reject: (error) => { + part.done = true; + outcome.reject(error); + } + }, + done: false, + gate: Promise.withResolvers() + }; + for (const key of spec.keys) + this.#unpublished.set(key, part); + this.#newest = part; + this.#queue.push(part); + this.#pump(); + return part; + } + /** The gate of the newest unpublished writer of `key`, or `undefined` when it has none. */ + gate(key) { + return this.#unpublished.get(key)?.gate.promise; + } + /** Opens once every part admitted so far is published or never will be. */ + drained() { + return this.#newest?.gate.promise; + } + /** Keys with an unpublished writer, for tests that bound memory. */ + get unpublished() { + return this.#unpublished.size; + } + #pump() { + if (this.#flight || this.#queue.length === 0) + return; + this.#flight = true; + const parts = this.#queue; + this.#queue = []; + void this.#flush(parts); + } + /** + * Send and publish `parts`, then what was admitted meanwhile. Never rejects: a throw the writer did not expect fails + * the Session and settles the parts (`#abandon()`), so no outcome or gate is stranded. + */ + async #flush(parts) { + try { + await this.#send(parts); + } catch (error) { + this.#abandon(parts, error); + } + this.#flight = false; + this.#pump(); + } + /** Store `parts` in one call, then publish them in order; settles every one of them. */ + async #send(parts) { + const stored = parts.filter((part) => part.writes !== void 0); + const seqs = []; + let result; + let rejected; + const failed = this.#host.failure(); + if (failed !== void 0) { + for (const part of parts) + this.#unpublish(part, new SessionFailed(failed.error)); + return; + } + if (stored.length > 0) { + try { + result = await this.#host.commit(stored.map((part) => part.writes), (index, seq) => { + seqs[index] = seq; + }, withoutAbortSignal(stored[0].context)); + } catch (error) { + rejected = { error }; + } + } + const failedMeanwhile = this.#host.failure(); + if (failedMeanwhile !== void 0) { + for (const part of parts) + this.#unpublish(part, new SessionFailed(failedMeanwhile.error)); + return; + } + await this.#publish(parts, seqs, result, rejected); + } + /** + * Publish the received parts and held ones in order, a macrotask apart, and settle every part (group commit §3.4). A + * refusal, a rejection, or a part whose adoption or own observer throws fails the Session once the parts before it + * are published and the host observers got the last one; the parts after it are not published, and reject with + * `SessionFailed`. What the failure decides (the outcomes, and the gates of the parts it concerns) is settled only + * once the Session failed, so no job waiting at such a gate, and no later outcome, goes on as if it had not. + */ + async #publish(parts, seqs, result, rejected) { + let stop2; + const failing = []; + let storedIndex = 0; + let published = 0; + for (const part of parts) { + const index = part.writes === void 0 ? void 0 : storedIndex++; + if (stop2 !== void 0) { + const outcome = rejected !== void 0 && index !== void 0 && stop2.external !== true ? { kind: "own", error: rejected.error } : SESSION_FAILED; + failing.push({ part, outcome, published: false }); + continue; + } + const seq = index === void 0 ? void 0 : seqs[index]; + if (index !== void 0 && seq === void 0) { + const error = rejected !== void 0 ? rejected.error : index === result?.stored && "refused" in result ? result.refused : new Error("Storage committed without adopting the batch"); + failing.push({ part, outcome: { kind: "own", error }, published: false }); + stop2 = { error, at: part.index }; + continue; + } + if (published++ > 0) + await hop(); + let failure2; + let external; + const publication = this.#host.publishing(() => { + external = this.#host.failure(); + if (external !== void 0) + return; + this.#unregister(part); + try { + if (part.writes !== void 0) + this.#host.stored(part.writes); + failure2 = part.publish(seq); + } catch (error) { + failure2 = { kind: "adoption", error }; + } + }, part.context); + if (publication !== void 0) + await publication; + if (external !== void 0) { + stop2 = { error: external.error, at: part.index, external: true }; + failing.push({ part, outcome: SESSION_FAILED, published: false }); + continue; + } + if (failure2?.kind === "adoption") { + failing.push({ part, outcome: { kind: "own", error: failure2.error }, published: true }); + stop2 = { error: failure2.error, at: part.index }; + continue; + } + if (rejected !== void 0) { + if (failure2 !== void 0) + this.#host.report(failure2.error, part.context); + failing.push({ part, outcome: { kind: "own", error: rejected.error }, published: true }); + continue; + } + if (failure2 !== void 0) + stop2 = { error: failure2.error, at: part.index }; + const failedMeanwhile = this.#host.failure(); + if (failedMeanwhile !== void 0 && failure2 === void 0) { + part.settle.reject(new SessionFailed(failedMeanwhile.error)); + } else + part.settle.resolve(); + this.#open(part); + } + if (rejected !== void 0 || stop2 !== void 0) { + await Promise.resolve(); + const own = failing.flatMap(({ part, outcome }) => outcome.kind === "own" ? [part.index] : []); + if (rejected !== void 0) + this.#host.fail(rejected.error, own[0], own); + else + this.#host.fail(stop2.error, stop2.at, own); + } + for (const { part, outcome, published: stored } of failing) { + const error = outcome.kind === "own" ? outcome.error : this.#failed(stop2.error); + if (stored) { + part.settle.reject(error); + this.#open(part); + } else + this.#unpublish(part, error); + } + const failure = this.#host.failure(); + if (failure !== void 0) { + const queued = this.#queue; + this.#queue = []; + for (const part of queued) + this.#unpublish(part, new SessionFailed(failure.error)); + } + } + /** + * A throw the writer itself did not expect while sending or publishing `parts` (a bug): fail the Session at the first + * of them and settle every one not settled yet, so no outcome, gate, or close waits on it forever. + */ + #abandon(parts, error) { + this.#host.fail(error, parts[0].index, []); + for (const part of parts) { + if (!part.done) + this.#unpublish(part, this.#failed(error)); + this.#unregister(part); + this.#open(part); + } + } + /** `SessionFailed` with the Session's failure, or with `error` until the Session records it. */ + #failed(error) { + const failure = this.#host.failure(); + return new SessionFailed(failure !== void 0 ? failure.error : error); + } + /** Settle a part that will never be published: discard it, reject it with `error`, and open its gate. */ + #unpublish(part, error) { + part.discard(); + part.settle.reject(error); + this.#unregister(part); + this.#open(part); + } + /** Drop the keys a part is still the newest writer of: it is published, or never will be. */ + #unregister(part) { + for (const key of part.keys) + if (this.#unpublished.get(key) === part) + this.#unpublished.delete(key); + } + /** Open a part's gate: the jobs waiting for it go on. The newest part's opens `drained()` too. */ + #open(part) { + part.gate.resolve(); + if (this.#newest === part) + this.#newest = void 0; + } +}; +function hop() { + if (typeof setImmediate === "function") + return new Promise((resolve2) => setImmediate(resolve2)); + const channel = new MessageChannel(); + return new Promise((resolve2) => { + channel.port1.onmessage = () => { + channel.port1.close(); + resolve2(); + }; + channel.port2.postMessage(void 0); + }); +} + +// node_modules/@earendil-works/pi-durable/dist/session/session.js +var NO_HOLDS = []; +var NO_OPERATIONS = []; +var NO_KEYS = []; +var MAX_OUTSTANDING = 256; +var ignore = () => { +}; +var SETTLED = Promise.resolve(); +var LISTENER = { kind: "listener_error" }; +var TELEMETRY = { kind: "host_error", callback: "telemetry" }; +var defaultRetention = 6e5; +function documentRetention(ms) { + return typeof ms === "number" && ms >= 0 ? ms : defaultRetention; +} +var DEFAULT_PERSIST_WITHIN_MS = 1e3; +function persistWithin(ms) { + return typeof ms === "number" && ms >= 0 ? ms : DEFAULT_PERSIST_WITHIN_MS; +} +var SessionImpl = class { + #storage; + /** Newest entry and head marker per conversation; none for a read-only Session, whose Storage another process writes. */ + #tails; + /** + * The current documents of each live task this Session created, so the commit that ends a task retires them without + * a scan. An entry starts with its task's creation and goes when the task is terminal: bounded by live tasks. + */ + #taskDocuments = /* @__PURE__ */ new Map(); + #documents = /* @__PURE__ */ new Map(); + /** Cached documents with no observer attached, by address, oldest use first, with the time of that use. */ + #idleDocuments = /* @__PURE__ */ new Map(); + /** Observers attached per document incarnation (record ID); a cached incarnation with any is never evicted. */ + #attachedDocuments = /* @__PURE__ */ new Map(); + #clock; + #documentRetentionMs; + #persistWithinMs; + /** Documents with held changes, by incarnation (record ID); each is pinned in the cache until they are stored. */ + #holds = /* @__PURE__ */ new Map(); + #holdTimer; + /** Refuse every commit with writes (`HarnessOptions.readOnly`). */ + #readOnly; + #timers; + /** The pending eviction: a timer for the oldest idle document, or a line job when the retention is 0. */ + #documentSweep; + #sweepJobs = 0; + /** Set once the host declined a background timer: then none is kept, and the end of each commit evicts what expired. */ + #documentTimersUnavailable = false; + /** Host commit observers (`observeCommits()`), each behind `guardObserver()`. */ + #commitListeners = /* @__PURE__ */ new Set(); + /** The Session's own listeners, such as its scheduler's: they keep memory in step with storage, so a throw fails it. */ + #internalListeners = /* @__PURE__ */ new Set(); + #closeListeners = /* @__PURE__ */ new Set(); + #host; + /** The record cache under the guard, which the writer applies each batch to at its publication. */ + #cached; + #writer; + /** The Storage jobs on the line read through: each read waits while its key has an unpublished writer. */ + #gated; + /** The end of the last line job: the line runs one job at a time. */ + #tail = Promise.resolve(); + /** Line index of the next job; outcomes are delivered in this order. */ + #nextIndex = 0; + /** The job on the line, while one runs: its index, and whether it waited at a gate. */ + #current; + /** Settles once every job so far has its outcome delivered. */ + #fence = Promise.resolve(); + #lastDelivered = -1; + /** Jobs that started on the line and have no outcome delivered yet (`MAX_OUTSTANDING`). */ + #outstanding = 0; + #room; + /** The line index whose outcome the failure is: every later job's outcome is `SessionFailed`, except `#ownOutcomes`. */ + #failAt; + /** Later jobs whose outcome is their own error all the same: the other parts of a storage call that rejected. */ + #ownOutcomes = /* @__PURE__ */ new Set(); + #closing; + #failure; + /** Set when close reaches the backend: calls that fail from then on fail because it closes. */ + #failed = Promise.withResolvers(); + #closed = Promise.withResolvers(); + get closed() { + return this.#closed.promise; + } + /** Internal: the error that failed the Session, if one did. */ + get failure() { + return this.#failure; + } + /** Internal: rejects with `SessionFailed` the moment the Session fails, before work underway has ended; never resolves. */ + get failed() { + return this.#failed.promise; + } + constructor(storage, now = Date.now, documentRetentionMs = () => void 0, setTimer, readOnly = false, persistWithinMs = () => void 0) { + this.#failed.promise.catch(() => { + }); + this.#readOnly = readOnly; + this.#cached = readOnly ? void 0 : new CachedStorage(storage); + this.#storage = new GuardedStorage(this.#cached ?? storage, this); + this.#gated = new GatedStorage(this.#storage, (key) => this.touch(key)); + this.#writer = new Writer({ + commit: (batches, receive, context) => this.#storage.commit(batches, receive, context), + stored: (writes) => { + this.#cached?.published(writes); + this.#tails?.apply(writes); + }, + publishing: (publish2, context) => this.#publishing(publish2, context), + failure: () => this.#failure, + fail: (error, at, own) => this.fail(error, void 0, at, own), + report: (error, context) => this.report(error, LISTENER, context) + }); + this.#tails = readOnly ? void 0 : new ConversationTails(); + this.#timers = hostTimers(setTimer, (error) => this.report(error, { kind: "host_error", callback: "setTimer" })); + this.#clock = () => { + try { + return now(); + } catch { + return Date.now(); + } + }; + this.#documentRetentionMs = () => { + try { + return documentRetention(documentRetentionMs()); + } catch { + return documentRetention(void 0); + } + }; + this.#persistWithinMs = () => { + try { + return persistWithin(persistWithinMs()); + } catch { + return persistWithin(void 0); + } + }; + this.#host = { + storage: this.#gated, + touch: (key) => this.touch(key), + now, + cached: (id) => { + const cached = this.#documents.get(id); + if (cached !== void 0) + this.#touchDocument(id); + return cached; + }, + load: (definition, addressId2, address, context) => this.#loadDocument(definition, addressId2, address, context), + install: (document) => { + this.#documents.set(document.addressId, document); + this.#touchDocument(document.addressId); + }, + evict: (id, recordId) => { + if (this.#documents.get(id)?.record.id === recordId) + this.#dropDocument(id); + }, + conversationCreated: (tx, record) => this.conversationCreated(tx, record), + taskDocuments: (taskId) => this.#taskDocuments.get(taskId)?.values(), + latestEntryId: (conversationId, context) => this.latestEntryId(conversationId, context), + latestHeadMarker: (conversationId, context) => this.latestHeadMarker(conversationId, void 0, context) + }; + } + /** The Storage behind the failure guard; every component reads and writes through it. */ + get storage() { + return this.#storage; + } + /** + * Internal, on the Session line: the newest entry ID visible from `conversationId`. Known from the Session's own + * commits when it owns its Storage, so it costs no Storage read after the first. + */ + latestEntryId(conversationId, context) { + const gate = this.#touchEntries(conversationId); + const latest = () => { + const read2 = async () => (await this.#storage.scanEntries({ conversationId }, 1, void 0, context)).items[0]?.id; + return this.#tails === void 0 ? read2() : this.#tails.latest(conversationId, read2); + }; + return gate === void 0 ? latest() : gate.then(latest); + } + /** + * Internal: the newest entry ID of `conversationId` as known from the Session's commits right now, without reading; + * `undefined` when not known (and always for a read-only Session). + */ + knownLatestEntryId(conversationId) { + return this.#tails?.peek(conversationId); + } + /** + * Internal, on the Session line: the newest visible head marker of `conversationId` at or before `atOrBefore`, any + * when `undefined`; known from the Session's own commits as `latestEntryId()` is. + */ + latestHeadMarker(conversationId, atOrBefore, context) { + const gate = this.#touchEntries(conversationId); + const marker = () => { + const read2 = () => this.#storage.findLatestHeadMarker(conversationId, atOrBefore, context); + return this.#tails === void 0 ? read2() : this.#tails.marker(conversationId, atOrBefore, read2); + }; + return gate === void 0 ? marker() : gate.then(marker); + } + /** + * On the line: wait for what an unpublished commit wrote of a conversation's entries, its appends and its creation, + * as reading them from Storage fails for a conversation not stored yet. + */ + #touchEntries(conversationId) { + const created = this.touch(conversationKey(conversationId)); + const appended = this.touch(appendKey(conversationId)); + if (created === void 0) + return appended; + return appended === void 0 ? created : Promise.all([created, appended]).then(ignore); + } + /** + * Internal, on the line: wait, while `key` has an unpublished writer (for `ALL_KEYS`, while anything is unpublished), + * until it is published, then check that the Session is healthy; `undefined` when there is nothing to wait for. A + * job's every read touches its key first, so it never observes state an earlier job admitted and the writer has not + * published. + */ + touch(key) { + const gate = key === ALL_KEYS ? this.#writer.drained() : this.#writer.gate(key); + if (gate === void 0) + return void 0; + if (this.#current !== void 0) + this.#current.hit = true; + return gate.then(() => this.#assertHealthy()); + } + commit(change, context, options) { + return this.commitWith(change, context, void 0, options); + } + /** + * Internal: fail the Session with `error`, the first wins, and report it once. Admission ends, and close listeners run + * now; they read the error from `failure`. The Storage guard calls this; the Harness also calls it for a throw in its + * scheduler's own commits. `at` is the line index of the job whose outcome the failure is, by default the job on the + * line: later jobs' outcomes become `SessionFailed`. + */ + fail(error, context, at, own) { + if (this.#failure !== void 0) + return; + this.#failure = { error }; + this.#failAt = at ?? this.#current?.index ?? this.#lastDelivered; + if (own !== void 0) + for (const index of own) + this.#ownOutcomes.add(index); + this.#failed.reject(new SessionFailed(error)); + this.close(BACKGROUND_CONTEXT).catch(() => { + }); + this.report(error, { kind: "storage_failed" }, context); + } + /** + * Internal commit exposing the concrete transaction and its internal operations, such as the reserved-ID root + * bootstrap and task replacement. `scope` sets the default `tx.createTask()` conversation and the task attributed to + * appended entries. + */ + commitWith(change, context, scope, options) { + let withinMs; + try { + this.assertUsable(); + withinMs = this.#deferral(options?.persistence); + } catch (error) { + return Promise.reject(error); + } + return this.#enqueue((index) => this.#runCommit(change, context, scope, withinMs, index)); + } + /** + * Internal: `commitWith()` for a commit of the scheduler's own whose outcome goes only to scheduler code. When it + * writes nothing and waited at no gate, it is equivalent to having run before every unpublished commit, so its + * outcome is delivered at once, ahead of theirs. One that writes is never exempt: its outcome waits for its own + * publication and every earlier outcome, so no invocation starts on a reservation that is not durable. + */ + commitInternal(change, context) { + try { + this.assertUsable(); + } catch (error) { + return Promise.reject(error); + } + return this.#enqueue((index) => this.#runCommit(change, context, void 0, void 0, index), true); + } + /** + * Internal, on the line: call `end` once the outcome of the job on the line settles, its commit published or never to + * be; at once off the line. + */ + onJobEnd(end) { + const job = this.#current; + if (job === void 0) { + end(); + return; + } + if (job.ends === void 0) + job.ends = [end]; + else + job.ends.push(end); + } + /** Internal: the Storage jobs on the line read through (`touch()`); off the line, use the plain one. */ + get lineStorage() { + return this.#gated; + } + /** How long a commit may stay in memory before it is stored; `undefined` when it is immediate. */ + #deferral(persistence) { + if (persistence?.kind !== "deferred") + return void 0; + const ms = persistence.withinMs; + if (ms === void 0) + return this.#persistWithinMs(); + if (typeof ms !== "number" || !(ms >= 0)) { + throw new TypeError("CommitPersistence.withinMs must be a number of milliseconds, 0 or more"); + } + return ms; + } + /** Internal: whether `tx` is the transaction of one of this Session's commits. */ + ownsTransaction(tx) { + return Transaction.ownedBy(tx, this.#host); + } + /** + * Internal: run a read-only job on the mutation line so multi-read derivations observe one committed state. It reads + * through `storage`, whose reads wait for the publication of what the line admitted before; its outcome comes after + * theirs. + */ + readOnLine(job) { + try { + this.assertUsable(); + } catch (error) { + return Promise.reject(error); + } + return this.#enqueue(async () => { + this.#assertHealthy(); + return { value: await job(this.#gated) }; + }); + } + /** + * Internal: a conversation document's current incarnation and value, for a job already running on the line (see + * `readOnLine()`). Absent documents are `undefined`. + */ + async conversationDocumentOnLine(token, conversationId, context) { + const definition = token.definition; + const resolved = resolveAddress(definition, [conversationId, context]); + const loaded = await this.#loadDocument(definition, resolved.id, resolved.address, context); + if (loaded === void 0) + return void 0; + checkRecordScope(definition, loaded.record); + checkRecordVersion(definition, loaded.record, loaded.storedVersion); + return { record: loaded.record, version: loaded.valueVersion, value: loaded.tracker.value }; + } + async snapshot(token, ...args) { + this.assertUsable(); + const definition = token.definition; + const resolved = resolveAddress(definition, args); + const context = args[resolved.nextArgument]; + const cached = this.#documents.get(resolved.id); + if (cached?.valueVersion === definition.version) + this.#touchDocument(resolved.id); + const loaded = cached?.valueVersion === definition.version ? cached : await this.#enqueue(async () => { + this.#assertHealthy(); + return { value: await this.#loadDocument(definition, resolved.id, resolved.address, context) }; + }); + if (loaded === void 0) + return void 0; + checkRecordScope(definition, loaded.record); + checkRecordVersion(definition, loaded.record, loaded.storedVersion); + return loaded.tracker.value; + } + watchDoc(token, ...args) { + try { + this.assertUsable(); + const definition = token.definition; + const resolved = resolveAddress(definition, args); + const context = args[resolved.nextArgument]; + const signal = context.abortSignal; + return this.#attachDocument(definition, resolved, context, (loaded) => { + const watch = this.#observeDocument(definition, loaded, createWatch, endWatch); + if (signal !== void 0) + watch.observeAbort(signal); + return watch; + }, abortWatch); + } catch (error) { + return Promise.reject(error); + } + } + observeDoc(token, ...args) { + try { + this.assertUsable(); + const definition = token.definition; + const resolved = resolveAddress(definition, args); + const observer = args[resolved.nextArgument]; + const context = args[resolved.nextArgument + 1]; + return this.#attachDocument(definition, resolved, context, (loaded) => { + const guarded = this.#observeDocument(definition, loaded, (_value, detach, report2) => guardObserver(observer, detach, report2), endGuarded); + return observation(loaded.tracker.value, guarded); + }, detachObservation); + } catch (error) { + return Promise.reject(error); + } + } + async snapshotAsOf(token, ...args) { + this.assertUsable(); + const definition = token.definition; + const resolved = resolveAddress(definition, args); + if (resolved.address.scope.kind !== "conversation") { + throw new TypeError("Session.snapshotAsOf() requires a conversation document"); + } + const conversationId = resolved.address.scope.conversationId; + const atValue = args[resolved.nextArgument]; + if (typeof atValue !== "number" || !Number.isSafeInteger(atValue)) { + throw new TypeError("Session.snapshotAsOf() requires an entry ID"); + } + const at = idFromNumber(atValue); + const context = args[resolved.nextArgument + 1]; + return this.#enqueue(async () => { + this.#assertHealthy(); + const storedEntry = await this.#gated.entry(conversationId, at, context); + if (storedEntry === void 0) { + throw new Error(`Entry ${at} is not visible from conversation ${conversationId}`); + } + const address = { + ...resolved.address, + scope: { kind: "conversation", conversationId: storedEntry.entry.conversationId } + }; + const record = await this.#gated.findDocument(address, storedEntry.commitSeq, context); + if (record === void 0) + return { value: void 0 }; + const stored = await this.#gated.document(record.id, storedEntry.commitSeq, context); + if (stored === void 0) { + throw new Error(`Historical document ${record.id} (${record.kind}) cannot be read`); + } + return { value: materializeDocument(definition, stored) }; + }); + } + close(context) { + if (this.#closing === void 0) { + const cleanup = withoutAbortSignal(context); + this.#closing = Promise.resolve().then(() => this.beforeClose()).then(() => this.#maintain(async () => { + await this.#drained(); + let unstored; + if (this.#failure === void 0 && this.#holds.size > 0) { + await this.#storeHolds(() => [...this.#holds.values()], cleanup).catch((error) => { + unstored = { error }; + }); + } + const observers = [...this.#commitListeners]; + this.#commitListeners.clear(); + const end = closeEnds(this.#failure).observer; + for (const observer of observers) + observer.end(end); + this.#internalListeners.clear(); + this.#documents.clear(); + this.#idleDocuments.clear(); + this.#attachedDocuments.clear(); + this.#holds.clear(); + this.#taskDocuments.clear(); + try { + await this.#storage.close(cleanup); + } catch (error) { + if (this.#failure === void 0) { + this.#failure = { error }; + this.report(error, { kind: "storage_failed" }); + } + throw error; + } + if (unstored !== void 0) + throw unstored.error; + })).finally(() => { + const failure = this.#failure; + this.#closed.resolve(failure === void 0 ? { kind: "closed" } : { kind: "failed", error: failure.error }); + }); + this.#notifyClose(); + } + return awaitWithContext(this.#closing, context); + } + /** Run the close listeners once, each on its own: one that fails is reported, and the rest still run. */ + #notifyClose() { + this.#documentSweep?.disarm?.(); + this.#documentSweep = void 0; + this.#holdTimer?.disarm(); + this.#holdTimer = void 0; + const listeners = [...this.#closeListeners]; + this.#closeListeners.clear(); + for (const listener of listeners) + contained(listener, (error) => this.report(error)); + } + /** + * Internal: the Session's failure, and errors of listeners, which never fail what ran them; `info` defaults to a + * listener. A plain Session drops them. + */ + report(_error, _info = LISTENER, _context) { + } + /** + * Runs inside every transaction that creates or forks a conversation, after the conversation record is staged. A + * plain Session stages nothing; a Harness stages its built-in documents. + */ + conversationCreated(_tx, _record) { + return Promise.resolve(); + } + /** + * Internal, for `beforeClose()`: on the line, after every commit admitted before the seal has settled, write what + * `writes()` returns then straight to Storage. Nothing is published, since the Session is closing; a failed Session + * writes nothing. + */ + writeAtClose(writes) { + return this.#maintain(async (index) => { + await this.#drained(); + if (this.#failure !== void 0) + return; + const batch = writes(); + if (batch.length === 0) + return; + const context = BACKGROUND_CONTEXT; + await this.#writer.admit({ + index, + writes: batch, + keys: [], + context, + publish: () => void 0, + discard: ignore + }).outcome; + }); + } + /** + * Keys a commit writes besides its records' (`Transaction.writeKeys()`), at its admission, on the line: a Harness + * adds the ownership memberships its task changes write. A plain Session adds none. + */ + membershipKeys(_tx) { + return NO_KEYS; + } + /** Runs after close seals admission and before the line closes Storage; must not reject. */ + beforeClose() { + return Promise.resolve(); + } + /** + * Attach a synchronous observer of every stored commit, with exactly what it stored (`CommitPublication`). Its + * `advance` runs one microtask after the commit's publication, which follows its storage call, in line order, before + * every wait the commit resolves and every abort it queues (in no order with watch listeners); it must not block or + * call Session operations. A throw is reported, detaches it, and ends it `listener_error`; `end` gets the Session's + * close after its last publication. + */ + observeCommits(observer) { + this.assertUsable(); + const guarded = guardObserver(observer, () => this.#commitListeners.delete(guarded), (error, context) => this.report(error, LISTENER, context)); + this.#commitListeners.add(guarded); + return { detach: () => guarded.detach() }; + } + /** + * Internal: follow every commit as memory adopts it (`ObservedCommit`), for the Session's own components, whose state + * follows memory. A throw leaves that state behind, so it fails the Session instead of being reported. They run at + * the commit's publication, synchronously, so they call no Storage method, run no task code, and contain every host + * callback; the waits they resolve and the aborts they queue run after host observers. + */ + followCommits(listener) { + this.assertUsable(); + this.#internalListeners.add(listener); + return () => this.#internalListeners.delete(listener); + } + /** + * Register a listener called synchronously when close begins, also when a failure closes the Session (`failure` is + * then set). It must not block or call Session operations; a throw is reported. + */ + subscribeClose(listener) { + this.assertUsable(); + this.#closeListeners.add(listener); + return () => this.#closeListeners.delete(listener); + } + /** Drop every loaded tracker on the mutation line, held changes stored first; later access cold-loads from Storage. */ + unloadDocuments() { + return this.#maintain(async () => { + if (this.#failure === void 0) + await this.#storeHolds(() => [...this.#holds.values()], BACKGROUND_CONTEXT); + this.#documents.clear(); + this.#idleDocuments.clear(); + }); + } + /** + * Internal, for tests: how many documents the cache holds, how many are idle, how many incarnations are pinned, how + * many sweep jobs were queued on the line so far, how many documents have held changes, how many live tasks have + * their documents indexed, and how many conversations have their newest entry kept. + */ + get documentCacheSizes() { + return { + cached: this.#documents.size, + idle: this.#idleDocuments.size, + attached: this.#attachedDocuments.size, + sweeps: this.#sweepJobs, + held: this.#holds.size, + taskDocuments: this.#taskDocuments.size, + tails: this.#tails?.size ?? 0 + }; + } + /** + * Internal, for tests that bound memory: jobs whose outcome is not delivered yet, keys with an unpublished writer, + * and record reads in flight in the cache. All three are 0 once the line is idle. + */ + get lineSizes() { + return { + outstanding: this.#outstanding, + unpublished: this.#writer.unpublished, + reads: this.#cached?.readsInFlight ?? 0 + }; + } + /** Note a use of a cached document: an unattached one becomes the newest idle one, and an eviction is scheduled. */ + #touchDocument(addressId2) { + const cached = this.#documents.get(addressId2); + if (cached === void 0 || this.#attachedDocuments.has(cached.record.id)) + return; + const now = this.#clock(); + const since = this.#idleDocuments.get(addressId2); + if (since !== void 0 && now - since < Math.min(1e3, this.#documentRetentionMs() / 10)) + return; + this.#idleDocuments.delete(addressId2); + this.#idleDocuments.set(addressId2, now); + if (this.#documentSweep === void 0 || this.#documentSweep.at > now + this.#documentRetentionMs()) { + this.#scheduleDocumentSweep(); + } + } + #dropDocument(addressId2) { + this.#documents.delete(addressId2); + this.#idleDocuments.delete(addressId2); + } + /** + * Schedule the eviction of the oldest idle document: on the line at once when the retention is 0, otherwise when it + * expires, by a background timer (`HarnessOptions.setTimer`), which never keeps the process alive. Where the host + * declines it, as the default does in Cloudflare Workers, none is kept: the end of each commit evicts what expired. + */ + #scheduleDocumentSweep() { + if (this.#closing !== void 0) + return; + let oldest; + for (const [addressId2, since] of this.#idleDocuments) { + if (this.#writer.gate(documentKey(addressId2)) !== void 0) + continue; + oldest = since; + break; + } + if (oldest === void 0) + return; + const at = oldest + this.#documentRetentionMs(); + if (this.#documentSweep !== void 0 && this.#documentSweep.at <= at) + return; + this.#documentSweep?.disarm?.(); + const sweep = { at, disarm: void 0 }; + const run2 = () => { + this.#sweepJobs++; + this.#maintain(async () => { + if (this.#documentSweep === sweep) + this.#documentSweep = void 0; + if (this.#closing === void 0) + this.#sweepDocuments(); + }).catch(() => { + }); + }; + const delay = at - this.#clock(); + this.#documentSweep = sweep; + if (delay <= 0) { + queueMicrotask(run2); + return; + } + if (this.#documentTimersUnavailable) { + this.#documentSweep = void 0; + return; + } + const disarm = this.#timers.background(run2, delay); + if (disarm === void 0) { + this.#documentTimersUnavailable = true; + this.#documentSweep = void 0; + return; + } + sweep.disarm = disarm; + } + /** On the line: evict the idle documents whose retention passed, oldest first, then schedule the next eviction. */ + #sweepDocuments() { + const expired = this.#clock() - this.#documentRetentionMs(); + for (const [addressId2, since] of this.#idleDocuments) { + if (since > expired) + break; + if (this.#writer.gate(documentKey(addressId2)) !== void 0) + continue; + this.#dropDocument(addressId2); + } + this.#scheduleDocumentSweep(); + } + /** Pin a cached incarnation for one observer; the returned release unpins it once, idle again after the last. */ + #pinDocument(addressId2, recordId) { + this.#attachedDocuments.set(recordId, (this.#attachedDocuments.get(recordId) ?? 0) + 1); + this.#idleDocuments.delete(addressId2); + let pinned = true; + return () => { + if (!pinned) + return; + pinned = false; + const count = (this.#attachedDocuments.get(recordId) ?? 1) - 1; + if (count > 0) { + this.#attachedDocuments.set(recordId, count); + return; + } + this.#attachedDocuments.delete(recordId); + if (this.#documents.get(addressId2)?.record.id === recordId) + this.#touchDocument(addressId2); + }; + } + async #runCommit(change, context, scope, withinMs, index) { + this.#assertHealthy(); + context.abortSignal?.throwIfAborted(); + const tx = new Transaction(this.#host, context, scope); + let result; + try { + result = await change(tx); + this.#assertHealthy(); + } catch (error) { + await tx.settleFailure(); + this.#sweepDocuments(); + throw error; + } + let writes; + try { + writes = await tx.settleSuccess(); + } catch (error) { + this.#sweepDocuments(); + throw error; + } + if (writes.length === 0) { + tx.discard(); + this.#sweepDocuments(); + return { value: result }; + } + if (this.#readOnly) { + tx.discard(); + this.#sweepDocuments(); + throw new ReadOnlySession("a commit with writes"); + } + const discard = () => tx.discard(); + if (withinMs !== void 0) { + const held = tx.holdable(); + if (held !== void 0) { + const part2 = this.#writer.admit({ + index, + writes: void 0, + keys: tx.writeKeys(), + context, + publish: () => this.#hold(tx, held, withinMs, context), + discard + }); + this.#sweepDocuments(); + return { value: result, after: part2.outcome }; + } + } + let membership = this.membershipKeys(tx); + if (!Array.isArray(membership)) { + try { + membership = await membership; + } catch (error) { + tx.discard(); + this.#sweepDocuments(); + throw error; + } + } + const taken = this.#holds.size === 0 ? NO_HOLDS : tx.takeHeld((id) => this.#holds.get(id)); + const keys = tx.writeKeys(); + for (const key of membership) + keys.push(key); + const part = this.#writer.admit({ + index, + writes, + keys, + context, + publish: (seq) => this.#adopt(tx, writes, taken, seq, context), + discard + }); + this.#sweepDocuments(); + return { value: result, after: part.outcome }; + } + /** + * Publish a stored commit (`Writer`), after the read caches took its writes: adopt it in memory and run its + * publication. A throw of the adoption leaves memory behind durable state; the writer fails the Session with it. + */ + #adopt(tx, writes, taken, seq, context) { + let documents; + try { + documents = tx.adopt(seq); + } catch (error) { + return { kind: "adoption", error }; + } + this.#indexTaskDocuments(tx, writes, documents, seq); + const failure = this.#publish(seq, writes, documents, context); + if (taken.length > 0) + this.#release(taken); + for (const document of documents.stored) + this.#touchDocument(addressId(document.record)); + return failure === void 0 ? void 0 : { kind: "listener", error: failure.error }; + } + /** + * At publication: keep `#taskDocuments` in step with a stored commit: the tasks it creates start with no documents, + * task documents it creates join their task, ones it retires leave, and tasks it ends leave the index. + */ + #indexTaskDocuments(tx, writes, documents, seq) { + for (const id of tx.createdTaskIds()) + this.#taskDocuments.set(id, /* @__PURE__ */ new Map()); + if (this.#taskDocuments.size === 0) + return; + for (const change of documents.stored) { + if (change.type !== "document" || change.record.scope.kind !== "task") + continue; + const known = this.#taskDocuments.get(change.record.scope.taskId); + if (known === void 0) + continue; + if (change.kind === "retire") + known.delete(change.record.id); + else if (change.record.createdAt === seq) + known.set(change.record.id, change.record); + } + for (const write of writes) { + if (write.type === "task" && write.value.state.status === "terminal") + this.#taskDocuments.delete(write.value.id); + } + } + /** + * Hold a deferred commit (`Transaction.holdable()`): adopt it in memory, queue its changes per document, pinned, by + * the earliest deadline of the document's held commits, and show it to the Session's own observers. + */ + #hold(tx, held, withinMs, context) { + let documents; + try { + documents = tx.adoptHeld(); + } catch (error) { + return { kind: "adoption", error }; + } + const deadline = this.#clock() + withinMs; + for (const { loaded, ops, base } of held) { + const id = loaded.record.id; + let hold = this.#holds.get(id); + if (hold === void 0) { + const unpin = this.#pinDocument(loaded.addressId, id); + hold = { loaded, pending: new PendingOps(), base: false, deadline, unpin }; + this.#holds.set(id, hold); + } + hold.pending.push(ops); + if (base) + hold.base = true; + if (deadline < hold.deadline) + hold.deadline = deadline; + } + this.#armHoldTimer(); + const publication = { kind: "memory", changes: documents }; + let failure; + for (const listener of [...this.#internalListeners]) { + try { + listener(publication, context); + } catch (error) { + failure ??= { kind: "listener", error }; + } + } + return failure; + } + /** + * Store the held changes `select` returns in one storage transaction, through the writer, from a job on the line. A + * barrier: they are selected once every commit admitted before is published. Memory already has them, so only + * `observeCommits()` observers see it, published as the writer publishes it. A failure fails the Session, as every + * Storage failure does. + */ + async #storeHolds(select, context) { + await this.#drained(); + const holds = select(); + if (holds.length === 0) + return; + const writes = []; + const changes = []; + const keys = []; + for (const hold of holds) { + const { record, tracker, valueVersion: version } = hold.loaded; + const value2 = tracker.value; + const stored = storeHeld(hold, NO_OPERATIONS, value2, version); + writes.push({ type: "document.change", id: record.id, content: stored.content }); + keys.push(documentKey(hold.loaded.addressId), incarnationKey(record.id)); + const conversationId = record.scope.kind === "conversation" ? record.scope.conversationId : void 0; + changes.push({ type: "document", kind: "change", record, conversationId, version, value: value2, ops: stored.ops }); + } + const publish2 = (seq) => { + for (const [index2, hold] of holds.entries()) { + if (writes[index2].content.kind === "base") + hold.loaded.deltasSinceBase = 0; + else + hold.loaded.deltasSinceBase++; + } + if (this.#commitListeners.size > 0) + this.#notifyHosts({ seq, changes }, context); + this.#release(holds); + return void 0; + }; + const index = this.#current.index; + await this.#writer.admit({ index, writes, keys, context, publish: publish2, discard: ignore }).outcome; + } + /** After their store: forget `holds`, unpin their documents, and move the timer to the next deadline. */ + #release(holds) { + for (const hold of holds) { + this.#holds.delete(hold.loaded.record.id); + hold.unpin(); + } + this.#armHoldTimer(); + } + /** + * Keep a foreground timer (Workers refuse background ones) for the earliest deadline of the held documents. When it + * fires, every held document is stored, in one storage transaction: a deadline is the latest time, and the others + * cost little more in the same transaction. Once fired, it stays until its job ran. + */ + #armHoldTimer() { + if (this.#closing !== void 0) + return; + let at = Infinity; + for (const hold of this.#holds.values()) + if (hold.deadline < at) + at = hold.deadline; + const armed = this.#holdTimer; + if (armed !== void 0 && (armed.fired || armed.at === at)) + return; + armed?.disarm(); + this.#holdTimer = void 0; + if (at === Infinity) + return; + const timer = { at, disarm: () => { + }, fired: false }; + const run2 = () => { + timer.fired = true; + this.#maintain(async () => { + if (this.#holdTimer === timer) + this.#holdTimer = void 0; + if (this.#closing !== void 0 || this.#failure !== void 0) + return; + await this.#storeHolds(() => [...this.#holds.values()], BACKGROUND_CONTEXT); + }).catch(() => { + }); + }; + this.#holdTimer = timer; + timer.disarm = this.#timers.foreground(run2, Math.max(0, at - this.#clock())); + } + /** + * At publication: publish a stored commit. Its telemetry events first, then the dispatch to `observeCommits()` + * observers, queued before the waits and aborts the observers wake, then the Session's own observers. Never throws: + * returns the first error of an own observer, which fails the Session once its storage call settled. + */ + #publish(seq, writes, documents, context) { + const changes = this.#commitListeners.size > 0 || this.#internalListeners.size > 0 ? [] : void 0; + for (const write of writes) { + switch (write.type) { + case "entry": + this.#event("pi.durable.entry", { "entry.id": write.value.id, "entry.kind": write.value.kind }, context); + changes?.push(write); + break; + case "submission": + if (write.value.status === "done" || write.value.status === "unanswered") { + this.#event("pi.durable.submission", { + "submission.id": write.value.id, + status: write.value.status, + "answer.entry_id": write.value.answer + }, context); + } + changes?.push(write); + break; + case "conversation": + case "task": + changes?.push(write); + } + } + if (changes === void 0) + return void 0; + const tables = changes.length; + for (const document of documents.observed) + changes.push(document); + const observed = { kind: "stored", seq, changes }; + if (this.#commitListeners.size > 0) { + const stored = documents.stored === documents.observed ? observed : { seq, changes: [...changes.slice(0, tables), ...documents.stored] }; + this.#notifyHosts(stored, context); + } + let failure; + for (const listener of [...this.#internalListeners]) { + try { + listener(observed, context); + } catch (error) { + failure ??= { error }; + } + } + return failure; + } + /** At publication: record a commit's telemetry event. A throwing adapter is reported, as publication must not throw. */ + #event(name, attributes, context) { + try { + context.telemetry.addEvent(name, attributes); + } catch (error) { + this.report(error, TELEMETRY, context); + } + } + /** + * At publication: call the `observeCommits()` observers with `publication` one microtask from now, and, queued + * before the Session's own observers run, before the waits they resolve and the aborts they queue. The observers are + * those attached when it runs; their guards report a throw. + */ + #notifyHosts(publication, context) { + void SETTLED.then(() => { + for (const observer of [...this.#commitListeners]) + observer.advance(publication, context); + }); + } + /** + * On the line, as one job: load the document at `resolved` and `attach` to it, so the attachment sees every commit + * after the value it starts from; `undefined` when absent. Cancelling `context` meanwhile rejects, after `cancel` + * undid an attachment made. + */ + async #attachDocument(definition, resolved, context, attach, cancel) { + const signal = context.abortSignal; + let cancelled = signal?.aborted ?? false; + const markCancelled = () => { + cancelled = true; + }; + signal?.addEventListener("abort", markCancelled, { once: true }); + try { + const attached = await this.#enqueue(async () => { + this.#assertHealthy(); + if (cancelled) + throw cancellationError(signal); + const loaded = await this.#loadDocument(definition, resolved.id, resolved.address, context); + if (cancelled) + throw cancellationError(signal); + return { value: loaded === void 0 ? void 0 : attach(loaded) }; + }); + if (attached === void 0) + return void 0; + if (cancelled) { + cancel(attached); + throw cancellationError(signal); + } + return attached; + } finally { + signal?.removeEventListener("abort", markCancelled); + } + } + /** + * Follow the address of the incarnation `loaded`, after checking the definition, with the observer `create` makes + * from its value, the idempotent detach, and the report of a listener error; returns that observer. It gets each + * committed change there, a retirement as a `retired` change with the last value it was given and no ops (a change + * in the retiring commit is not published), and a later incarnation as a root replacement. When the commit makes the + * owner task of a task document terminal, no later commit can change the address: after its changes the commit + * subscription and the pin go, and `ownerEnded` tells the observer, which stays subscribed to the Session's close + * until it ends (its detach drops that). `end` gets the Session's close. The current incarnation is pinned in the + * cache. The detach runs before `end`; once it ran, nothing more of the commit underway reaches the observer or pins + * anything for it. `create` and `ownerEnded` are module functions where they can be, so a watch keeps no closure of + * its caller. + */ + #observeDocument(definition, loaded, create, ownerEnded) { + checkRecordScope(definition, loaded.record); + checkRecordVersion(definition, loaded.record, loaded.storedVersion); + const addressId2 = loaded.addressId; + const address = loaded.record; + let incarnation = loaded.record.id; + let value2 = loaded.tracker.value; + let version = loaded.valueVersion; + let unpin = this.#pinDocument(addressId2, incarnation); + let unsubscribeCommit = () => { + }; + let unsubscribeClose = () => { + }; + let attached = true; + const detach = () => { + if (!attached) + return; + attached = false; + unsubscribeCommit(); + unsubscribeClose(); + unpin(); + }; + const observer = create(loaded.tracker.value, detach, (error) => this.report(error)); + unsubscribeCommit = this.followCommits((publication, context) => { + if (!attached) + return; + let ownerEnds = false; + for (const change of publication.changes) { + if (change.type === "task") { + const scope = address.scope; + if (scope.kind === "task" && change.value.id === scope.taskId && change.value.state.status === "terminal") { + ownerEnds = true; + } + continue; + } + if (change.type !== "document") + continue; + if (change.record.id !== incarnation && !atAddress(change.record, address)) + continue; + if (change.kind === "retire") { + if (change.record.id !== incarnation) + continue; + const last = value2; + incarnation = void 0; + value2 = void 0; + unpin(); + observer.advance({ kind: "value", value: last, ops: NO_OPERATIONS, retired: true }, context); + } else if (change.record.id !== incarnation || change.version !== version) { + if (change.record.id !== incarnation) { + incarnation = change.record.id; + unpin(); + unpin = this.#pinDocument(addressId2, incarnation); + } + version = change.version; + value2 = change.value; + observer.advance({ kind: "value", value: value2, ops: [["r", value2]], retired: false }, context); + } else { + if (change.ops.length === 0) + continue; + value2 = change.value; + observer.advance({ kind: "value", value: value2, ops: change.ops, retired: false }, context); + } + if (!attached) + return; + } + if (!ownerEnds) + return; + unsubscribeCommit(); + unpin(); + ownerEnded(observer); + }); + unsubscribeClose = this.subscribeClose(() => { + detach(); + observer.end(closeEndOf(observer, closeEnds(this.#failure))); + }); + return observer; + } + async #loadDocument(definition, addressId2, address, context) { + const gate = this.touch(documentKey(addressId2)); + if (gate !== void 0) + await gate; + const cached = this.#documents.get(addressId2); + if (cached?.valueVersion === definition.version) { + this.#touchDocument(addressId2); + return cached; + } + if (cached !== void 0) { + const id = cached.record.id; + await this.#storeHolds(() => { + const hold = this.#holds.get(id); + return hold === void 0 ? NO_HOLDS : [hold]; + }, context); + this.#dropDocument(addressId2); + } + const record = await this.#storage.findDocument(address, "current", context); + if (record === void 0) + return void 0; + const stored = await this.#storage.document(record.id, "current", context); + if (stored === void 0) + throw new Error(`Current document ${record.id} (${record.kind}) cannot be read`); + const value2 = materializeDocument(definition, stored); + const loaded = { + addressId: addressId2, + record: stored.record, + storedVersion: stored.version, + valueVersion: definition.version, + deltasSinceBase: stored.deltasSinceBase, + tracker: track(value2) + }; + this.#documents.set(addressId2, loaded); + this.#touchDocument(addressId2); + return loaded; + } + /** + * Run `job` on the line, after the jobs before it, and deliver its outcome in line order: once the jobs before it + * have theirs, and once its commit, if it admitted one, is published. With `exempt`, a job that admitted no commit and + * waited at no gate is delivered as soon as it has its outcome: it is equivalent to having run before every + * unpublished commit. A job + * whose outcome comes after the one a failure is gets `SessionFailed` instead. At most `MAX_OUTSTANDING` jobs wait + * for their delivery; beyond it the line waits. + */ + #enqueue(work, exempt = false) { + const job = { index: this.#nextIndex++, hit: false }; + const ran = this.#tail.then(async () => { + while (this.#outstanding >= MAX_OUTSTANDING) { + this.#room ??= Promise.withResolvers(); + await this.#room.promise; + } + this.#outstanding++; + return this.#onLine(job, work); + }); + this.#tail = ran.then(ignore, ignore); + const outcome = ran.then((result) => { + if (result.after === void 0) { + this.#ended(job); + return result.value; + } + return result.after.then(() => { + this.#ended(job); + return result.value; + }, (error) => { + this.#ended(job); + throw error; + }); + }, (error) => { + this.#ended(job); + throw error; + }); + outcome.catch(ignore); + const fence = this.#fence; + this.#fence = fence.then(() => outcome).then(ignore, ignore); + const index = job.index; + const deliver = (fenced) => (fenced ? fence.then(() => outcome) : outcome).then((value2) => { + this.#delivered(index, fenced); + if (this.#poisoned(index)) + throw new SessionFailed(this.#failure.error); + return value2; + }, (error) => { + this.#delivered(index, fenced); + throw this.#poisoned(index) ? new SessionFailed(this.#failure.error) : error; + }); + return exempt ? ran.then((result) => deliver(job.hit || result.after !== void 0), () => deliver(job.hit)) : deliver(true); + } + /** Whether job `index` comes after the failure's boundary without an outcome of its own: it gets `SessionFailed`. */ + #poisoned(index) { + return this.#failAt !== void 0 && index > this.#failAt && !this.#ownOutcomes.has(index); + } + /** The job's outcome settled: run what waited for it (`onJobEnd()`). */ + #ended(job) { + const ends = job.ends; + if (ends === void 0) + return; + job.ends = void 0; + for (const end of ends) + end(); + } + /** Run a job of the Session's own upkeep on the line: no outcome to deliver, so no fence and no `SessionFailed`. */ + #maintain(work) { + const job = { index: this.#nextIndex++, hit: false }; + const ran = this.#tail.then(() => this.#onLine(job, work)); + this.#tail = ran.then(ignore, ignore); + return ran; + } + /** Hold the line for job `index` until its line part, through admission, is done. Gates are its touches' own. */ + async #onLine(job, work) { + this.#current = job; + try { + return await work(job.index); + } finally { + this.#current = void 0; + } + } + /** A `*` barrier: once every part admitted so far is published, or never will be. */ + async #drained() { + const drained = this.#writer.drained(); + if (drained !== void 0) + await drained; + } + /** + * Run one commit's publication inside the Storage's own scope (`Storage.publishing`), such as a store host's batch; + * directly without one. `undefined` when it ran at once, else settles once it ran. A Storage that throws instead of + * running it is reported, and the publication runs directly: the commit is stored, so it must be published. + */ + #publishing(publish2, context) { + const publishing = this.#storage.publishing; + if (publishing === void 0) { + publish2(); + return void 0; + } + const done = Promise.withResolvers(); + let ran = false; + const once = () => { + if (ran) + return; + ran = true; + try { + publish2(); + } finally { + done.resolve(); + } + }; + try { + publishing(once, context); + } catch (error) { + this.report(error, LISTENER, context); + once(); + } + return done.promise; + } + /** Job `index` has its outcome: let the line go on past `MAX_OUTSTANDING`. */ + #delivered(index, fenced) { + if (fenced) + this.#lastDelivered = index; + this.#outstanding--; + const room = this.#room; + if (room !== void 0 && this.#outstanding < MAX_OUTSTANDING) { + this.#room = void 0; + room.resolve(); + } + } + /** Internal: throw `SessionFailed` when failed, else an error when closing. */ + assertUsable() { + this.#assertHealthy(); + if (this.#closing !== void 0) + throw new Error("Session is closed"); + } + #assertHealthy() { + if (this.#failure !== void 0) + throw new SessionFailed(this.#failure.error); + } +}; +function contained(callback, onError) { + try { + const result = callback(); + if (typeof result?.then === "function") + Promise.resolve(result).catch(onError); + } catch (error) { + onError(error); + } +} +function guardObserver(observer, detach, report2) { + let attached = { observer, detach, report: report2 }; + const release = () => { + const released = attached; + attached = void 0; + released?.detach(); + return released; + }; + const fault = (current, error, context) => { + current.report(error, context); + if (release() !== void 0) { + const end = { kind: "listener_error", error: toError2(error) }; + contained(() => current.observer.end(end), current.report); + } + }; + return { + advance: (call, context) => { + const current = attached; + if (current === void 0) + return; + try { + const result = current.observer.advance(call, context); + if (typeof result?.then === "function") { + Promise.resolve(result).catch((error) => fault(current, error, context)); + } + } catch (error) { + fault(current, error, context); + } + }, + end: (end) => { + const ending = release(); + if (ending !== void 0) + contained(() => ending.observer.end(end), ending.report); + }, + detach: () => { + release(); + } + }; +} +function toError2(error) { + if (error instanceof Error) + return error; + try { + return new Error(String(error)); + } catch { + return new Error(Object.prototype.toString.call(error)); + } +} +var ENDED2 = { kind: "ended" }; +function closeEnds(failure) { + if (failure !== void 0) { + const failed = { kind: "failed", error: failure.error }; + return { watch: failed, observer: failed }; + } + return { watch: ENDED2, observer: { kind: "failed", error: new Error("session closed") } }; +} +function closeEndOf(follower, ends) { + return follower instanceof Watch ? ends.watch : ends.observer; +} +function observation(value2, guarded) { + return { value: value2, detach: () => guarded.detach() }; +} +function createWatch(value2, detach, report2) { + return new Watch(value2, detach, report2); +} +function abortWatch(watch) { + watch.abort(); +} +function detachObservation(attached) { + attached.detach(); +} +function endWatch(watch) { + watch.endAfterDelivery(); +} +function endGuarded(guarded) { + guarded.end(ENDED2); +} +function atAddress(record, address) { + if (record.kind !== address.kind || record.key !== address.key) + return false; + switch (record.scope.kind) { + case "session": + return address.scope.kind === "session"; + case "conversation": + return address.scope.kind === "conversation" && address.scope.conversationId === record.scope.conversationId; + case "task": + return address.scope.kind === "task" && address.scope.taskId === record.scope.taskId; + } +} +function cancellationError(signal) { + return signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError"); +} +var GuardedStorage = class { + #storage; + #latch; + /** Backend calls underway, also those off the Session line, which close waits for before it closes the backend. */ + #underway = /* @__PURE__ */ new Set(); + #closing = false; + constructor(storage, latch) { + this.#storage = storage; + this.#latch = latch; + } + /** The backend's own scope for a publication (`Storage.publishing`), when it has one; not a call to guard. */ + get publishing() { + return scopeOf(this.#storage); + } + /** + * Guarded like every call, but its outcome is the Session writer's to judge: it publishes the batches received first, + * then fails the Session for a refusal or a rejection, and for a Session that failed meanwhile. + */ + async commit(batches, receive, context) { + this.#assertHealthy(); + if (this.#closing) + throw new Error("Session is closed"); + const call = (async () => this.#storage.commit(batches, receive, context))(); + this.#underway.add(call); + try { + return await call; + } finally { + this.#underway.delete(call); + } + } + mintId() { + return this.#call(void 0, () => this.#storage.mintId()); + } + conversation(id, context) { + return this.#call(context, () => this.#storage.conversation(id, context)); + } + scanConversations(query, limit, cursor, context) { + return this.#call(context, () => this.#storage.scanConversations(query, limit, cursor, context)); + } + entry(first, second, third) { + if (third === void 0) { + const context = second; + return this.#call(context, () => this.#storage.entry(first, context)); + } + return this.#call(third, () => this.#storage.entry(first, second, third)); + } + findLatestHeadMarker(conversationId, atOrBeforeEntryId, context) { + return this.#call(context, () => this.#storage.findLatestHeadMarker(conversationId, atOrBeforeEntryId, context)); + } + scanEntries(query, limit, cursor, context) { + return this.#call(context, () => this.#storage.scanEntries(query, limit, cursor, context)); + } + task(id, context) { + return this.#call(context, () => this.#storage.task(id, context)); + } + scanTasks(query, limit, cursor, context) { + return this.#call(context, () => this.#storage.scanTasks(query, limit, cursor, context)); + } + submission(id, context) { + return this.#call(context, () => this.#storage.submission(id, context)); + } + scanSubmissions(query, limit, cursor, context) { + return this.#call(context, () => this.#storage.scanSubmissions(query, limit, cursor, context)); + } + submissionByRequest(conversationId, requestId, context) { + return this.#call(context, () => this.#storage.submissionByRequest(conversationId, requestId, context)); + } + findDocument(address, at, context) { + return this.#call(context, () => this.#storage.findDocument(address, at, context)); + } + document(id, at, context) { + return this.#call(context, () => this.#storage.document(id, at, context)); + } + scanDocuments(query, limit, cursor, context) { + return this.#call(context, () => this.#storage.scanDocuments(query, limit, cursor, context)); + } + /** + * Close the backend once every call underway has settled, so none outlives it or fails after `closed` settles. New + * calls are refused from here on: a paged read must not start its next page while the backend closes. + */ + async close(context) { + this.#closing = true; + await Promise.allSettled([...this.#underway]); + return this.#storage.close(context); + } + /** + * Run one backend call under the guard. `read` is a read's context; `commit()` and `mintId()` pass none, so nothing + * exempts their errors: once a batch is admitted, whether it committed is unknown. A call still underway when another + * fails the Session ends with `SessionFailed` too, whatever it returns: nothing it read or wrote is used. + */ + async #call(read2, run2) { + this.#assertHealthy(); + if (this.#closing) + throw new Error("Session is closed"); + let result; + const call = (async () => run2())(); + this.#underway.add(call); + try { + result = await call; + } catch (error) { + this.#assertHealthy(); + const exempt = read2 !== void 0 && (error instanceof StorageRequestError || read2.abortSignal?.aborted === true); + if (!exempt) + this.#latch.fail(error); + throw error; + } finally { + this.#underway.delete(call); + } + this.#assertHealthy(); + return result; + } + #assertHealthy() { + const failure = this.#latch.failure; + if (failure !== void 0) + throw new SessionFailed(failure.error); + } +}; + +// node_modules/@earendil-works/pi-durable/dist/harness/agent.js +var DEFAULT_RETRY_POLICY = { + enabled: true, + maxRetries: 3, + baseDelayMs: 2e3, + maxAgentDelayMs: 6e4 +}; +var DEFAULT_COMPACTION_POLICY = { + enabled: true, + reserveTokens: 16384, + keepRecentTokens: 2e4, + backgroundTokens: 32768 +}; +var DEFAULT_PROGRESS_POLICY = { + partialIntervalMs: 100, + outputIntervalMs: 100, + persistWithinMs: 1e3 +}; +var INSTRUCTIONS_KEY = "instructions"; +var AgentDoc = defineDoc({ + kind: "pi.agent", + version: 1, + scope: "conversation", + history: "rewindable", + fork: "asOf", + initial: () => ({}), + checkpointWhen: () => true +}); +var DEFAULT_CONTEXT_RETENTION_MS = 6e5; +var DEFAULT_RESTART_LIMIT = 5; +function restartLimit(limit) { + return typeof limit === "number" && limit >= 1 ? Math.floor(limit) : DEFAULT_RESTART_LIMIT; +} +function resolveSettings(settings) { + const extensions = settings?.extensions; + return { + ...extensions === void 0 ? {} : { extensions }, + stream: { ...settings?.stream }, + retry: { ...DEFAULT_RETRY_POLICY, ...settings?.retry }, + compaction: { ...DEFAULT_COMPACTION_POLICY, ...settings?.compaction }, + // Field by field, so an explicitly undefined interval keeps its default. + progress: { + partialIntervalMs: settings?.progress?.partialIntervalMs ?? DEFAULT_PROGRESS_POLICY.partialIntervalMs, + outputIntervalMs: settings?.progress?.outputIntervalMs ?? DEFAULT_PROGRESS_POLICY.outputIntervalMs, + persistWithinMs: persistWithin(settings?.progress?.persistWithinMs) + }, + toolExecution: settings?.toolExecution ?? "parallel", + steeringMode: settings?.steeringMode ?? "one-at-a-time", + followUpMode: settings?.followUpMode ?? "one-at-a-time", + contextRetentionMs: settings?.contextRetentionMs ?? DEFAULT_CONTEXT_RETENTION_MS, + documentRetentionMs: documentRetention(settings?.documentRetentionMs), + afterFailedRun: settings?.afterFailedRun ?? "keep", + restartLimit: restartLimit(settings?.restartLimit) + }; +} +async function configure(tx, conversationId, change) { + const state = await tx.doc(AgentDoc, conversationId); + applyChange(state, change); +} +async function addTools(tx, conversationId, added) { + const state = await tx.doc(AgentDoc, conversationId); + const tools = state.tools; + if (Array.isArray(tools)) { + for (const name of added) + if (!tools.includes(name)) + tools.push(name); + } else if (tools?.remove.some((name) => added.includes(name))) { + state.tools = { remove: tools.remove.filter((name) => !added.includes(name)) }; + } + const modelTools = state.modelTools; + if (Array.isArray(modelTools)) { + for (const name of added) + if (!modelTools.includes(name)) + modelTools.push(name); + return; + } + const remove = (modelTools?.remove ?? []).filter((name) => !added.includes(name)); + const add = [...modelTools?.add ?? []]; + for (const name of added) + if (!add.includes(name)) + add.push(name); + state.modelTools = { ...remove.length === 0 ? {} : { remove }, add }; +} +function applyChange(state, change) { + const set = (key, value2) => { + if (value2 === void 0) + return; + if (value2 === null) + delete state[key]; + else + state[key] = value2; + }; + set("model", change.model === void 0 || change.model === null ? change.model : { ...change.model }); + set("thinkingLevel", change.thinkingLevel); + const extensions = change.extensions; + set("extensions", extensions === void 0 || extensions === null ? extensions : isList(extensions) ? names(extensions) : { + ...extensions.add === void 0 ? {} : { add: names(extensions.add) }, + ...extensions.remove === void 0 ? {} : { remove: names(extensions.remove) } + }); + const tools = change.tools; + set("tools", tools === void 0 || tools === null ? tools : isList(tools) ? names(tools) : { remove: names(tools.remove) }); + const modelTools = change.modelTools; + set("modelTools", modelTools === void 0 || modelTools === null ? modelTools : isList(modelTools) ? names(modelTools) : { + ...modelTools.remove === void 0 ? {} : { remove: names(modelTools.remove) }, + ...modelTools.add === void 0 ? {} : { add: names(modelTools.add) } + }); + set("instructions", change.instructions); + set("cwd", change.cwd); + const maxTurns = change.maxTurns; + if (maxTurns !== void 0 && maxTurns !== null && !(Number.isSafeInteger(maxTurns) && maxTurns >= 1)) { + throw new RangeError(`maxTurns must be an integer 1 or more, got ${String(maxTurns)}`); + } + set("maxTurns", maxTurns); +} +function isList(value2) { + return Array.isArray(value2); +} +function names(items) { + return items.map((item) => item.name); +} +async function createAgent(tx, conversation) { + if (conversation.parent !== void 0) + return; + const agent = await tx.doc(AgentDoc, conversation.id); + if (conversation.owner === void 0) + return; + const owner = await tx.doc(AgentDoc, conversation.owner.conversationId); + Object.assign(agent, copyJson(owner)); +} +function agentHooks(agent, taskName) { + const handlers = []; + for (const extension of agent.extensions) { + for (const hook2 of extension.hooks ?? []) { + if (hook2.task === taskName) + handlers.push({ extension: extension.name, handlers: hook2.handlers }); + } + } + return handlers; +} +function sectionExtension(agent, key) { + let found; + for (const extension of agent.extensions) { + const provides = extension.sections?.some((section2) => section2.key === key) === true; + const wraps = extension.wraps?.some((wrap) => "section" in wrap && wrap.section === key) === true; + if (provides || wraps) + found = extension.name; + } + return found; +} +function toolExtension(agent, name) { + let found; + for (const extension of agent.extensions) { + const provides = extension.tools?.some((tool) => tool.name === name) === true; + const wraps = extension.wraps?.some((wrap) => "tool" in wrap && wrap.tool === name) === true; + if (provides || wraps) + found = extension.name; + } + return found; +} +function resolveAgent(state, snapshot, settings, report2) { + const extensions = selectExtensions(state?.extensions, snapshot, settings); + const composed = /* @__PURE__ */ new Map(); + for (const extension of extensions) + for (const tool of extension.tools ?? []) + composed.set(tool.name, tool); + const sections = /* @__PURE__ */ new Map(); + for (const extension of extensions) { + for (const section2 of extension.sections ?? []) + sections.set(section2.key, section2); + } + for (const extension of extensions) { + for (const wrap of extension.wraps ?? []) { + const wrapReport = (error) => report2(error, extension.name); + if ("tool" in wrap) + applyWrap(composed, wrap.tool, (tool) => wrap.wrap(tool), (tool) => tool.name, wrapReport); + else + applyWrap(sections, wrap.section, (section2) => wrap.wrap(section2), (section2) => section2.key, wrapReport); + } + } + const enabled = filterTools([...composed.values()], state?.tools); + const callableBy = (caller) => (tool) => tool.callers === void 0 || tool.callers.includes(caller); + const modelCallable = enabled.filter(callableBy("model")); + const tools = offeredTools(modelCallable, state?.modelTools); + const offered = new Set(tools); + const deferred = modelCallable.filter((tool) => tool.deferred === true && !offered.has(tool)); + const callable = enabled.filter(callableBy("tools")); + const instructions = state?.instructions; + const agentSections = [...sections.values()]; + if (instructions !== void 0) + agentSections.push({ key: INSTRUCTIONS_KEY, render: () => instructions }); + const agent = { + ...state?.model === void 0 ? {} : { model: state.model }, + thinkingLevel: state?.thinkingLevel ?? "off", + extensions, + tools, + callable, + deferred, + sections: agentSections, + ...instructions === void 0 ? {} : { instructions }, + ...state?.cwd === void 0 ? {} : { cwd: state.cwd }, + ...state?.maxTurns === void 0 ? {} : { maxTurns: state.maxTurns } + }; + return agent; +} +function offeredTools(tools, filter) { + if (Array.isArray(filter)) + return filterTools(tools, filter); + const removed = new Set(filter?.remove ?? []); + const kept = tools.filter((tool) => tool.deferred !== true && !removed.has(tool.name)); + const byName = new Map(tools.map((tool) => [tool.name, tool])); + const loaded = [...new Set(filter?.add ?? [])].flatMap((name) => { + const tool = byName.get(name); + return tool?.deferred === true && !removed.has(name) ? [tool] : []; + }); + return [...kept, ...loaded]; +} +function filterTools(tools, filter) { + if (filter === void 0) + return tools; + if (Array.isArray(filter)) { + const byName = new Map(tools.map((tool) => [tool.name, tool])); + return [...new Set(filter)].flatMap((name) => { + const tool = byName.get(name); + return tool === void 0 ? [] : [tool]; + }); + } + const removed = new Set(filter.remove); + return tools.filter((tool) => !removed.has(tool.name)); +} +function selectExtensions(stored, snapshot, settings) { + let selected; + if (Array.isArray(stored)) + selected = stored; + else { + const base = settings.extensions?.map((extension) => extension.name) ?? snapshot.installed().map((e) => e.name); + const edit = stored; + const removed = new Set(edit?.remove ?? []); + selected = [...base, ...edit?.add ?? []].filter((name) => !removed.has(name)); + } + const extensions = []; + for (const name of new Set(selected)) { + const extension = snapshot.extension(name); + if (extension !== void 0) + extensions.push(extension); + } + return extensions; +} +function applyWrap(items, target, wrap, nameOf, report2) { + const item = items.get(target); + if (item === void 0) + return; + try { + const wrapped = wrap(item); + if (nameOf(wrapped) !== target) + throw new Error(`Wrapper renamed ${target} to ${nameOf(wrapped)}`); + items.set(target, wrapped); + } catch (error) { + items.delete(target); + report2(error); + } +} + +// node_modules/@earendil-works/pi-ai/dist/utils/estimate.js +var CHARS_PER_TOKEN = 3.5; +var ESTIMATED_IMAGE_CHARS = 4800; +function calculateContextTokens(usage) { + return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite; +} +function safeJsonStringify(value2) { + try { + return JSON.stringify(value2) ?? "undefined"; + } catch { + return "[unserializable]"; + } +} +function estimateTextAndImageContentChars(content) { + if (typeof content === "string") + return content.length; + let chars = 0; + for (const block of content) + chars += block.type === "text" ? block.text.length : ESTIMATED_IMAGE_CHARS; + return chars; +} +function estimateTextTokens(text) { + return Math.ceil(text.length / CHARS_PER_TOKEN); +} +function estimateTextAndImageContentTokens(content) { + return Math.ceil(estimateTextAndImageContentChars(content) / CHARS_PER_TOKEN); +} +function estimateMessageTokens(message) { + let chars = 0; + if (message.role === "system") { + return estimateTextTokens(getSystemMessageText(message)) + estimateToolsTokens(message.toolsAdded) + estimateToolsTokens(message.toolsRemoved); + } + if (message.role === "user") + return estimateTextAndImageContentTokens(message.content); + if (message.role === "toolResult") + return estimateTextAndImageContentTokens(message.content); + for (const block of message.content) { + if (block.type === "text") { + chars += block.text.length; + } else if (block.type === "thinking") { + chars += block.thinking.length; + } else { + chars += block.name.length + safeJsonStringify(block.arguments).length; + } + } + return Math.ceil(chars / CHARS_PER_TOKEN); +} +function estimateToolsTokens(tools) { + if (!tools || tools.length === 0) + return 0; + return estimateTextTokens(safeJsonStringify(tools)); +} + +// node_modules/@earendil-works/pi-ai/dist/utils/retry.js +function buildProviderErrorPattern(patterns) { + return new RegExp(patterns.join("|"), "i"); +} +var NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([ + // OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's + // Zen API. These are subscription/account limits, not transient throttles. + "GoUsageLimitError", + "FreeUsageLimitError", + // OpenCode Go subscription-limit text asks users to enable available-balance + // usage after rolling/weekly/monthly limits are reached. + "Monthly usage limit reached", + "available balance", + // Generic quota/budget/billing exhaustion. `insufficient_quota` is OpenAI's + // quota/billing error code; the other strings cover common gateway wording. + "insufficient_quota", + "out of budget", + "quota exceeded", + "billing", + // Sign in with ChatGPT: the subscription's shared usage limit, which resets + // after hours rather than seconds. + "subscription_sharing_usage_limit_exceeded", + // Sign in with ChatGPT on a ChatGPT Business plan: a usage limit set by the + // workspace admin. Only the admin can raise it. + "subscription_sharing_workplace_individual_usage_limit_exceeded", + // Zhipu/Z.ai (open.bigmodel.cn) error code 1308: the plan's usage limit is + // reached, sent as HTTP 429. It resets after hours, not seconds (#11537). + '"code"\\s*:\\s*"?1308(?![0-9])' +]); +var RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([ + // Generic provider load, HTTP status, and server-side transient failures. + "overloaded", + "server_busy", + "servers are currently busy", + "currently experiencing high demand", + "model is at capacity", + "rate.?limit", + "too many requests", + // Status codes must not be part of a longer word or number, e.g. a request id or byte count (#11057). + "(? captureContextBounds(session, line, conversationId, context, at, visible)); + if (bounds === void 0) + return { view: emptyView(), range: void 0 }; + freezeJson(bounds.head); + const current = at === void 0; + let range; + if (previous === void 0 || previous.bounds.head?.id !== bounds.head?.id) { + const entries2 = freezeJson(await scanRange(storage, conversationId, rangeQuery(bounds), context)); + range = deriveRange(bounds, entries2, current); + } else if (bounds.tail === previous.bounds.tail) { + range = previous; + } else if (bounds.tail < previous.bounds.tail) { + range = deriveRange(bounds, previous.entries.filter((entry2) => entry2.id <= bounds.tail), false); + } else { + const minEntryId = idFromNumber(previous.bounds.tail + 1); + const added = await scanRange(storage, conversationId, { minEntryId, maxEntryId: bounds.tail }, context); + range = extendRange(previous, bounds, freezeJson(added), current); + } + if (range.current && session.knownLatestEntryId(conversationId) !== range.bounds.tail) { + range = { ...range, current: false }; + } + const { view: view2 } = range; + return { + view: { + ...view2, + entries: [...view2.entries], + contributions: [...view2.contributions], + messages: [...view2.messages] + }, + range + }; +} +async function readContext(session, storage, conversationId, context, at) { + const bounds = await session.readOnLine((line) => captureContextBounds(session, line, conversationId, context, at)); + return deriveContext(storage, conversationId, bounds, context); +} +async function deriveContext(storage, conversationId, bounds, context) { + if (bounds === void 0) + return emptyView(); + return deriveRange(bounds, await scanRange(storage, conversationId, rangeQuery(bounds), context), false).view; +} +function emptyView() { + return { head: void 0, entries: [], contributions: [], messages: [] }; +} +function rangeEntry(range, id) { + const entries2 = range.entries; + let low = 0; + let high = entries2.length - 1; + while (low <= high) { + const middle = low + high >>> 1; + const entry2 = entries2[middle]; + if (entry2.id === id) + return entry2; + if (entry2.id < id) + low = middle + 1; + else + high = middle - 1; + } + return void 0; +} +function advanceRange(range, appended) { + if (!range.current || appended.length === 0) + return range; + const added = freezeJson(appended); + let head = range.bounds.head; + for (const entry2 of added) + if (entry2.head !== void 0) + head = entry2; + const bounds = { head, tail: added.at(-1).id }; + if (head?.id === range.bounds.head?.id) + return extendRange(range, bounds, added, true); + const start = head.head; + if (range.bounds.head !== void 0 && start < range.bounds.head.head) + return void 0; + const entries2 = [...range.entries, ...added].filter((entry2) => entry2.id >= start); + return deriveRange(bounds, entries2, true); +} +function deriveRange(bounds, entries2, current) { + const edits = /* @__PURE__ */ new Map(); + for (const entry2 of entries2) + for (const edit of entry2.edits ?? []) + edits.set(edit.target, edit); + const active = selectActive(bounds.head, entries2); + const contributions = active.map((entry2) => contribute(entry2, edits.get(entry2.id))); + const { settled, open } = settle([], contributions.flat()); + const baseline = findBaseline(bounds.head, active); + const messages = leadWithSystem([...settled, ...orderToolResults(open)], baseline); + const view2 = { head: bounds.head, entries: active, contributions, messages }; + return { bounds, entries: entries2, view: view2, edited: new Set(edits.keys()), settled, open, baseline, current }; +} +function extendRange(previous, bounds, added, current) { + const entries2 = [...previous.entries, ...added]; + if (added.some((entry2) => entry2.edits !== void 0 || entry2.head !== void 0 || previous.edited.has(entry2.id))) { + return deriveRange(bounds, entries2, current); + } + const contributions = added.map((entry2) => contribute(entry2, void 0)); + const { settled, open } = settle(previous.settled, [...previous.open, ...contributions.flat()]); + const baseline = previous.baseline !== void 0 ? previous.baseline : findBaseline(bounds.head, added); + const view2 = { + head: bounds.head, + entries: [...previous.view.entries, ...added], + contributions: [...previous.view.contributions, ...contributions], + messages: leadWithSystem([...settled, ...orderToolResults(open)], baseline) + }; + return { bounds, entries: entries2, view: view2, edited: previous.edited, settled, open, baseline, current }; +} +function findBaseline(head, entries2) { + for (const entry2 of entries2) { + if (head !== void 0 && entry2.id <= head.id) + continue; + if (SystemEntry.is(entry2)) + return entry2.model?.find((message) => message.role === "system") ?? null; + if (head === void 0 && carriesSystemMessage(entry2)) + return null; + } + return void 0; +} +function carriesSystemMessage(entry2) { + const isSystem = (message) => message.role === "system"; + return (entry2.model?.some(isSystem) ?? false) || (entry2.edits?.some((edit) => edit.action === "replace" && edit.messages.some(isSystem)) ?? false); +} +function leadWithSystem(messages, baseline) { + const index = messages.findIndex((message) => message.role === "system"); + if (index <= 0) + return messages; + const system = messages[index]; + if (system !== baseline && messages.slice(0, index).some((message) => message.role !== "user")) { + return messages; + } + return [system, ...messages.slice(0, index), ...messages.slice(index + 1)]; +} +function contribute(entry2, edit) { + if (edit?.action === "omit") + return Object.freeze([]); + const contributed = edit?.action === "replace" ? edit.messages : entry2.model ?? []; + return Object.freeze(contributed.filter((message) => message.role !== "assistant" || !EXCLUDED_STOP_REASONS.has(message.stopReason))); +} +var deeplyFrozen = /* @__PURE__ */ new WeakSet(); +function freezeJson(value2) { + if (value2 === null || typeof value2 !== "object" || deeplyFrozen.has(value2)) + return value2; + for (const child of Object.values(value2)) + freezeJson(child); + Object.freeze(value2); + deeplyFrozen.add(value2); + return value2; +} +function settle(settled, open) { + const last = open.findLastIndex((message) => message.role === "assistant"); + if (last <= 0) + return { settled, open }; + return { settled: [...settled, ...orderToolResults(open.slice(0, last))], open: open.slice(last) }; +} +function rangeQuery(bounds) { + const head = bounds.head; + return head === void 0 ? { maxEntryId: bounds.tail } : { minEntryId: head.head, maxEntryId: bounds.tail }; +} +async function scanRange(storage, conversationId, range, context) { + const entries2 = []; + let cursor; + do { + const page2 = await storage.scanEntries({ conversationId, ...range }, SCAN_PAGE_SIZE2, cursor, context); + entries2.push(...page2.items); + cursor = page2.next; + } while (cursor !== void 0); + return entries2.reverse(); +} +function selectActive(head, range) { + return head === void 0 ? range : [head, ...range.filter((entry2) => entry2.head === void 0)]; +} +function orderToolResults(messages) { + const ordered = []; + for (let index = 0; index < messages.length; index++) { + const message = messages[index]; + if (message.role === "toolResult") + continue; + ordered.push(message); + if (message.role !== "assistant") + continue; + const calls = message.content.filter((content) => content.type === "toolCall"); + if (calls.length === 0) + continue; + const results = /* @__PURE__ */ new Map(); + for (let next = index + 1; next < messages.length && messages[next].role !== "assistant"; next++) { + const candidate = messages[next]; + if (candidate.role === "toolResult" && !results.has(candidate.toolCallId)) { + results.set(candidate.toolCallId, next); + } + } + for (const call of calls) { + const resultIndex = results.get(call.id); + ordered.push(resultIndex === void 0 ? missingResult(call, message.timestamp) : messages[resultIndex]); + } + } + return ordered; +} +function missingResult(call, timestamp) { + return freezeJson({ + role: "toolResult", + toolCallId: call.id, + toolName: call.name, + content: [{ type: "text", text: MISSING_RESULT_TEXT }], + isError: true, + details: { reason: "missing_result" }, + timestamp + }); +} + +// node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +var OVERFLOW_PATTERNS = [ + /prompt (?:is )?too long/i, + // Anthropic and z.ai token overflow + /prompt exceeds max length/i, + // z.ai CN endpoint token overflow + /request_too_large/i, + // Anthropic request byte-size overflow (HTTP 413) + /input is too long for requested model/i, + // Amazon Bedrock + /exceeds the context window/i, + // OpenAI (Completions & Responses API) + /exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\d,]+ tokens?|\s*\([\d,]+\))/i, + // OpenAI-compatible proxies (LiteLLM) + /context window exceeded/i, + // LiteLLM pre-call check (ContextWindowExceededError) + /input token count.*exceeds the maximum/i, + // Google (Gemini) + /maximum prompt length is \d+/i, + // xAI (Grok) + /reduce the length of the messages/i, + // Groq + /maximum context length is \d+ tokens/i, + // OpenRouter (most backends) + /exceeds (?:the )?maximum allowed input length of [\d,]+ tokens?/i, + // OpenRouter/Poolside + /input \(\d+ tokens\) is longer than the model'?s context length \(\d+ tokens\)/i, + // Together AI + /exceeds the limit of \d+/i, + // GitHub Copilot + /exceeds the available context size/i, + // llama.cpp server + /greater than the context length/i, + // LM Studio + /context window exceeds limit/i, + // MiniMax + /exceeded model token limit/i, + // Kimi For Coding + /too large for model with \d+ maximum context length/i, + // Mistral + /prompt has [\d,]+ tokens?, but the configured context size is [\d,]+ tokens?/i, + // DS4 server + /model_context_window_exceeded/i, + // z.ai non-standard finish_reason surfaced as error text + /prompt too long; exceeded (?:max )?context length/i, + // Ollama explicit overflow error + /range of input length should be/i, + // DashScope / Qwen Token Plan + /context[_ ]length[_ ]exceeded/i, + // Generic fallback + /too many tokens/i, + // Generic fallback + /token limit exceeded/i, + // Generic fallback + // HTTP 413 means request-size overflow regardless of provider or body text. + // Match raw SDK errors and formatProviderError's prefix, not a status mentioned in the body. + /^(?:[\w -]+ API error \(413\):|413(?:\s|:|$))/i +]; +var CEREBRAS_BODYLESS_OVERFLOW_PATTERN = /^4(?:00|13)\s*(?:status code)?\s*\(no body\)/i; +var NON_OVERFLOW_PATTERNS = [ + /^(Throttling error|Service unavailable):/i, + // AWS Bedrock non-overflow errors (human-readable prefixes from formatBedrockError) + /rate limit/i, + // Generic rate limiting + /too many requests/i + // Generic HTTP 429 style +]; +function isContextOverflow(message, contextWindow) { + if (message.stopReason === "error" && message.errorMessage) { + const isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage)); + if (!isNonOverflow) { + if (OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage))) { + return true; + } + if (message.provider === "cerebras" && CEREBRAS_BODYLESS_OVERFLOW_PATTERN.test(message.errorMessage)) { + return true; + } + } + } + if (contextWindow && message.stopReason === "stop") { + const inputTokens = message.usage.input + message.usage.cacheRead; + if (inputTokens > contextWindow) { + return true; + } + } + if (contextWindow && message.stopReason === "length" && message.usage.output === 0) { + const inputTokens = message.usage.input + message.usage.cacheRead; + if (inputTokens >= contextWindow * 0.99) { + return true; + } + } + return false; +} + +// node_modules/@earendil-works/pi-durable/dist/harness/inbox.js +var InboxDoc = defineDoc({ + kind: "pi.inbox", + version: 1, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({ items: [] }), + checkpointWhen: (value2) => value2.items.length === 0 +}); +async function prepareBoundary(tx, conversationId, modes) { + const head = (await tx.latestHeadMarker(conversationId))?.head; + const inbox = await tx.doc(InboxDoc, conversationId); + return { + conversationId, + inbox, + steeringMode: modes.steeringMode, + followUpMode: modes.followUpMode, + head + }; +} +async function applyBoundary(tx, boundary, at, now) { + const { conversationId, inbox } = boundary; + const items = inbox.items; + const reset = hasQueuedReset(items); + const final = at === "final" || reset; + const pick = (mode, queueMode) => { + const indexes = items.flatMap((item, index) => item.mode === mode ? [index] : []); + return queueMode === "all" ? indexes : indexes.slice(0, 1); + }; + const writes = items.flatMap((item, index) => item.mode === "write" ? [index] : []); + const users = [...pick("steer", boundary.steeringMode), ...final ? pick("followUp", boundary.followUpMode) : []]; + users.sort((a, b) => a - b); + let first; + for (const index of writes) { + const item = items[index]; + const draft = item.entry; + if (isStale(boundary, draft)) { + tx.settleSubmission(item.id, { status: "unanswered", reason: "stale" }); + continue; + } + const entry2 = await tx.appendEntry(conversationId, draft); + if (draft.head !== void 0) + boundary.head = draft.head === "self" ? entry2.id : draft.head; + tx.placeSubmission(item.id, entry2.id); + first ??= entry2.id; + } + const placed = []; + for (const index of users) { + const item = items[index]; + const entry2 = await appendInput(tx, conversationId, item.content, item.entry, now); + tx.placeSubmission(item.id, entry2.id); + placed.push(item.id); + first ??= entry2.id; + } + const removed = [...writes, ...users].sort((a, b) => b - a); + for (const index of removed) + items.splice(index, 1); + return { users: placed, first, reset }; +} +function appendInput(tx, conversationId, content, entry2, now) { + const message = { role: "user", content, timestamp: now }; + if (entry2 === void 0) + return tx.appendEntry(UserEntry, conversationId, { model: [message] }); + return tx.appendEntry(conversationId, { ...pickInputEntry(entry2), model: [message] }); +} +function pickInputEntry({ kind, data }) { + const picked = data === void 0 ? { kind } : { kind, data }; + return copyJson(picked, { omitUndefinedProperties: true }); +} +function isDisplayOnly(entry2) { + return entry2.model === void 0 && entry2.head === void 0 && entry2.edits === void 0; +} +function hasQueuedReset(items) { + return items.some((item) => item.mode === "write" && item.entry.head === "self"); +} +function isStale(boundary, entry2) { + return typeof entry2.head === "number" && boundary.head !== void 0 && entry2.head < boundary.head; +} +async function removeInboxItem(tx, conversationId, id) { + const items = (await tx.doc(InboxDoc, conversationId)).items; + const index = items.findIndex((item) => item.id === id); + if (index >= 0) + items.splice(index, 1); +} +async function withdrawQueuedInputs(tx, conversationId, reason = "aborted") { + const items = (await tx.doc(InboxDoc, conversationId)).items; + for (let index = items.length - 1; index >= 0; index--) { + const item = items[index]; + if (item.mode === "write") + continue; + tx.settleSubmission(item.id, { status: "unanswered", reason }); + items.splice(index, 1); + } +} + +// node_modules/@earendil-works/pi-durable/dist/harness/json.js +function assignJson(target, key, value2, plan) { + if (plan?.kind === "keep") + return; + const slots = target; + const current = key === "__proto__" && !Object.hasOwn(slots, key) ? void 0 : slots[key]; + const fields = plan?.kind === "fields" ? plan.fields : void 0; + if (isRecord(current) && isRecord(value2)) { + for (const name of Object.keys(current)) + if (!Object.hasOwn(value2, name)) + delete current[name]; + for (const [name, child] of Object.entries(value2)) + assignJson(current, name, child, fields?.get(name)); + return; + } + if (Array.isArray(current) && Array.isArray(value2) && current.length <= value2.length) { + const items = current; + for (let index = 0; index < value2.length; index++) { + if (index < items.length) + assignJson(items, index, value2[index], fields?.get(index)); + else + items.push(value2[index]); + } + return; + } + if (plan?.kind === "append" && typeof current === "string" && typeof value2 === "string" && !Array.isArray(target) && current.length + plan.text.length === value2.length) { + appendText(target, String(key), plan.text); + return; + } + if (current !== value2) + slots[key] = value2; +} +function isRecord(value2) { + return typeof value2 === "object" && value2 !== null && !Array.isArray(value2); +} + +// node_modules/@earendil-works/pi-durable/dist/harness/partial-changes.js +var PartialChanges = class { + #text = /* @__PURE__ */ new Map(); + #toolCalls = /* @__PURE__ */ new Map(); + /** Record what `event` changed. */ + observe(event) { + switch (event.type) { + case "text_delta": + case "thinking_delta": { + const field = event.type === "text_delta" ? "text" : "thinking"; + const pending = this.#text.get(event.contentIndex); + if (pending?.field === field) + pending.text += event.delta; + else + this.#text.set(event.contentIndex, { field, text: event.delta }); + return; + } + case "toolcall_start": + this.#toolCalls.set(event.contentIndex, { + parser: new StreamingJsonParser(), + changes: [], + committed: false + }); + return; + case "toolcall_delta": { + const call = this.#toolCalls.get(event.contentIndex); + if (call === void 0) + return; + for (const change of call.parser.append(event.delta)) { + if (change.path.length === 0 && !isRecord2(change.kind === "set" ? value(change) : null)) { + this.#toolCalls.delete(event.contentIndex); + return; + } + call.changes.push(change); + } + return; + } + case "text_end": + case "thinking_end": + this.#text.delete(event.contentIndex); + return; + case "toolcall_end": + this.#toolCalls.delete(event.contentIndex); + return; + } + } + /** + * Take what changed since the last call, for a commit of `message`, a copy of the partial. Clears the arguments of + * tracked tool calls in `message`: the commit writes them from the changes. Call `restore()` if the commit fails. + */ + take(message) { + const blocks = /* @__PURE__ */ new Map(); + for (const [index, { field, text }] of this.#text) { + blocks.set(index, { kind: "fields", fields: /* @__PURE__ */ new Map([[field, { kind: "append", text }]]) }); + } + this.#text = /* @__PURE__ */ new Map(); + const toolCalls = /* @__PURE__ */ new Map(); + for (const [index, call] of this.#toolCalls) { + const block = message.content[index]; + if (block?.type !== "toolCall") + continue; + toolCalls.set(index, { changes: call.changes, snapshot: block.arguments }); + block.arguments = {}; + blocks.set(index, { kind: "fields", fields: /* @__PURE__ */ new Map([["arguments", { kind: "keep" }]]) }); + call.changes = []; + } + return { + plan: { kind: "fields", fields: /* @__PURE__ */ new Map([["content", { kind: "fields", fields: blocks }]]) }, + toolCalls + }; + } + /** + * Write `message` with what `commit` took into `generation.message`: the message leaf by leaf with the plan, then the + * argument changes. A tracked call whose block is new here gets its arguments from its changes, which then start at + * its first piece; when the committed message lost a call whose changes were already committed (another writer reset + * it), the call falls back to its snapshot from now on. + */ + commit(generation, message, commit) { + const committedBlocks = generation.message?.content.length ?? 0; + const apply2 = []; + for (const [index, { changes, snapshot }] of commit.toolCalls) { + const call = this.#toolCalls.get(index); + if (call === void 0) + continue; + const block = message.content[index]; + if (index >= committedBlocks && call.committed && block?.type === "toolCall") { + this.#toolCalls.delete(index); + block.arguments = snapshot; + continue; + } + call.committed = true; + apply2.push([index, changes]); + } + assignJson(generation, "message", message, commit.plan); + const content = generation.message?.content ?? []; + for (const [index, changes] of apply2) { + const block = content[index]; + if (block?.type !== "toolCall") + continue; + for (const change of changes) + applyChange2(block, change); + } + } + /** Put back what a failed commit took, so the next commit applies it first. */ + restore(commit) { + for (const [index, { changes }] of commit.toolCalls) { + const call = this.#toolCalls.get(index); + if (call !== void 0) + call.changes = [...changes, ...call.changes]; + } + } +}; +function applyChange2(block, change) { + const key = change.path.at(-1); + if (key === void 0) { + const root2 = change.kind === "set" ? value(change) : void 0; + if (isRecord2(root2)) + block.arguments = root2; + return; + } + let parent = block.arguments; + for (const segment of change.path.slice(0, -1)) { + parent = parent[segment]; + } + const slots = parent; + if (change.kind === "set") + slots[key] = value(change); + else if (Array.isArray(parent)) + slots[key] = `${slots[key]}${change.text}`; + else + appendText(parent, String(key), change.text); +} +function value(change) { + return change.value; +} +function isRecord2(value2) { + return typeof value2 === "object" && value2 !== null && !Array.isArray(value2); +} + +// node_modules/@earendil-works/pi-durable/dist/harness/prompt.js +function replaySections(messages) { + const shown = /* @__PURE__ */ new Map(); + for (const message of messages) { + if (message.role !== "system" || message.sections === void 0) + continue; + for (const [key, value2] of Object.entries(message.sections)) { + if (value2 === null) + shown.delete(key); + else + shown.set(key, value2); + } + } + return shown; +} +async function renderSections(sections, input, shown, report2, context) { + const desired = /* @__PURE__ */ new Map(); + for (const section2 of sections) { + let text; + try { + text = await section2.render(input, context); + } catch (error) { + if (context.abortSignal?.aborted) + throw error; + report2(error, section2); + const kept = shown.get(section2.key); + if (kept !== void 0) + desired.set(section2.key, kept); + continue; + } + if (text === void 0) + continue; + desired.set(section2.key, section2.tag === false ? text : `<${section2.key}> +${text} +`); + } + return desired; +} +function planSystemEntries(view2, desired, tools, timestamp) { + const head = view2.head; + if (head !== void 0 && !view2.entries.some((entry2) => SystemEntry.is(entry2) && entry2.id > head.id)) { + const edits = view2.entries.filter((entry2) => SystemEntry.is(entry2)).map((entry2) => ({ target: entry2.id, action: "omit" })); + const baseline = systemEntry(Object.fromEntries(desired), { toolsRemoved: [], toolsAdded: tools.map(toToolDeclaration) }, timestamp); + return [edits.length === 0 ? baseline : { ...baseline, edits }]; + } + const sections = planSections(replaySections(view2.messages), desired); + const changes = planTools(getCurrentTools(view2.messages), tools); + if (changes.toolsRemoved.length === 0 && changes.toolsAdded.length === 0) { + return sections.map((patch) => systemEntry(patch, void 0, timestamp)); + } + if (sections.length === 0) + return [systemEntry(void 0, changes, timestamp)]; + return sections.map((patch, index) => systemEntry(patch, index === sections.length - 1 ? changes : void 0, timestamp)); +} +function planTools(offered, desired) { + const wanted = new Map(desired.map((tool) => [tool.name, tool])); + const kept = offered.filter((tool) => { + const next = wanted.get(tool.name); + return next !== void 0 && declarationsEqual(tool, next); + }); + const keptNames = new Set(kept.map((tool) => tool.name)); + const added = desired.filter((tool) => !keptNames.has(tool.name)); + const replayed = [...kept, ...added]; + if (replayed.some((tool, index) => tool.name !== desired[index].name)) { + return { + toolsRemoved: offered.map((tool) => ({ name: tool.name })), + toolsAdded: desired.map(toToolDeclaration) + }; + } + return { + toolsRemoved: offered.filter((tool) => !keptNames.has(tool.name)).map((tool) => ({ name: tool.name })), + toolsAdded: added.map(toToolDeclaration) + }; +} +function planSections(shown, desired) { + const patchedOrder = [ + ...[...shown.keys()].filter((key) => desired.has(key)), + ...[...desired.keys()].filter((key) => !shown.has(key)) + ]; + const desiredOrder = [...desired.keys()]; + if (patchedOrder.some((key, index) => key !== desiredOrder[index])) { + return [Object.fromEntries([...shown.keys()].map((key) => [key, null])), Object.fromEntries(desired)]; + } + const patch = {}; + for (const [key, value2] of shown) { + const next = desired.get(key); + if (next !== value2) + patch[key] = next ?? null; + } + for (const [key, value2] of desired) + if (!shown.has(key)) + patch[key] = value2; + return Object.keys(patch).length === 0 ? [] : [patch]; +} +function systemEntry(sections, tools, timestamp) { + const message = { + role: "system", + content: "", + ...sections === void 0 ? {} : { sections }, + ...tools === void 0 || tools.toolsRemoved.length === 0 ? {} : { toolsRemoved: tools.toolsRemoved }, + ...tools === void 0 || tools.toolsAdded.length === 0 ? {} : { toolsAdded: tools.toolsAdded }, + timestamp + }; + return { model: [message] }; +} + +// node_modules/@earendil-works/pi-ai/dist/utils/uuid.js +var MAX_UUID_V7_TIMESTAMP = 281474976710655; +var MAX_SEQUENCE = (1n << 41n) - 1n; +var lastOrdinaryTimestamp = -1; +var sequence; +function uuidv7(timestampMs) { + const requestedTimestamp = timestampMs ?? Date.now(); + if (!Number.isInteger(requestedTimestamp) || requestedTimestamp < 0 || requestedTimestamp > MAX_UUID_V7_TIMESTAMP) { + throw new RangeError(`UUIDv7 timestamp must be an integer between 0 and ${MAX_UUID_V7_TIMESTAMP}`); + } + const effectiveTimestamp = timestampMs === void 0 ? Math.max(requestedTimestamp, lastOrdinaryTimestamp) : timestampMs; + if (timestampMs === void 0) + lastOrdinaryTimestamp = effectiveTimestamp; + const bytes = new Uint8Array(16); + globalThis.crypto.getRandomValues(bytes); + if (sequence === void 0) { + sequence = BigInt(bytes[1]) << 32n | BigInt(bytes[2]) << 24n | BigInt(bytes[3]) << 16n | BigInt(bytes[4]) << 8n | BigInt(bytes[5]); + } else { + if (sequence === MAX_SEQUENCE) + throw new RangeError("UUIDv7 generator sequence exhausted"); + sequence++; + } + const timestamp = BigInt(effectiveTimestamp); + for (let index = 5; index >= 0; index--) { + bytes[index] = Number(timestamp >> BigInt((5 - index) * 8)) & 255; + } + bytes[6] = 112 | Number(sequence >> 37n & 0x0fn); + bytes[7] = Number(sequence >> 29n & 0xffn); + bytes[8] = 128 | Number(sequence >> 23n & 0x3fn); + bytes[9] = Number(sequence >> 15n & 0xffn); + bytes[10] = Number(sequence >> 7n & 0xffn); + bytes[11] = Number((sequence & 0x7fn) << 1n) | bytes[11] & 1; + const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")); + return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`; +} + +// node_modules/@earendil-works/pi-durable/dist/harness/provider.js +var ProviderDoc = defineDoc({ + kind: "pi.provider", + version: 1, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({ sessionId: uuidv7() }), + checkpointWhen: () => true +}); +async function ensureProviderSessionId(runtime, context) { + const existing = await runtime.snapshot(ProviderDoc, runtime.conversationId, context); + if (existing !== void 0) + return existing.sessionId; + let created; + await runtime.commit(async (tx) => { + created = (await tx.doc(ProviderDoc, runtime.conversationId)).sessionId; + return void 0; + }, context); + if (created === void 0) + throw new Error(`Conversation ${runtime.conversationId} has no provider session ID`); + return created; +} + +// node_modules/@earendil-works/pi-durable/dist/harness/telemetry.js +var entry = { + description: "A transcript entry was committed; content remains in the transcript.", + attributes: { + "entry.id": { type: "number", required: true, description: "Transcript entry ID.", cardinality: "high" }, + "entry.kind": { type: "string", required: true, description: "Entry kind." } + } +}; +var reportAttributes = { + type: { + type: "string", + required: true, + description: "Report kind (`Report.kind`).", + values: [ + "storage_failed", + "task_faulted", + "task_interrupted", + "migration_failed", + "task_outdated", + "task_error", + "extension_error", + "host_error", + "listener_error" + ] + }, + reason: { + type: "string", + required: false, + description: "Fixed report reason, when present.", + values: ["threw", "restart_limit", "interrupted", "missing_task", "task_too_old", "migration_failed"] + }, + extension: { type: "string", required: false, description: "Registered extension name, when present." }, + "task.id": { type: "number", required: false, description: "Task ID, when present.", cardinality: "high" } +}; +var report = { + description: "A report was raised; no error payload is recorded.", + attributes: reportAttributes +}; +var submission = { + description: "A submission was settled.", + attributes: { + "submission.id": { type: "number", required: true, description: "Submission ID.", cardinality: "high" }, + status: { type: "string", required: true, values: ["done", "unanswered"], description: "Settlement." }, + "answer.entry_id": { type: "number", required: false, description: "Answer entry ID.", cardinality: "high" } + } +}; +var DURABLE_TELEMETRY_SCHEMA = defineTelemetrySchema({ + version: 1, + spans: { + "pi.durable.submit": { + description: "Public submission admission: with its commit for submit(draft, context); the admission only for submit(tx, draft), whose result is provisional (a later throw or storage failure of the caller's commit leaves no submission) and whose commit events go to the caller's commit context. Inputs and continues start root traces linked to their callers; writes are children. Internal admissions emit phase events only.", + parents: { kind: "any" }, + startAttributes: { + "submission.type": { + type: "string", + required: true, + values: ["input", "write", "continue"], + description: "Submission type." + }, + "conversation.id": { type: "number", required: true, description: "Conversation ID.", cardinality: "high" } + }, + endAttributes: { + "submission.id": { type: "number", description: "Admitted submission ID.", cardinality: "high" }, + result: { + type: "string", + values: ["queued", "placed", "done"], + description: "Admission result; stale writes report done." + } + }, + events: { "pi.durable.entry": entry, "pi.durable.submission": submission, "pi.durable.report": report }, + status: { default: "ok", errorWhen: "Admission failed." } + }, + "pi.durable.phase": { + description: "One task phase invocation, including its decision commit, never a wait or restart.", + parents: { kind: "any" }, + startAttributes: { + "task.id": { type: "number", required: true, description: "Task ID.", cardinality: "high" }, + "task.name": { type: "string", required: true, description: "Registered task name." }, + phase: { type: "string", required: true, description: "Invoked checkpoint phase." }, + kind: { type: "string", required: true, values: ["run", "abort"], description: "Invocation kind." }, + attempt: { type: "number", required: false, description: "Checkpoint attempt, when present." }, + resumed: { + type: "boolean", + required: true, + description: "First invocation of a task loaded in this process." + } + }, + endAttributes: { + outcome: { type: "string", description: "next=, waiting, sleeping, done, faulted, or aborted." }, + "tool.name": { type: "string", description: "Called tool name." }, + "tool.call_id": { type: "string", description: "Transcript tool call ID.", cardinality: "high" } + }, + events: { + "pi.durable.entry": entry, + "pi.durable.submission": submission, + "pi.durable.report": report, + "pi.durable.checkpoint": { + description: "The running checkpoint's phase changed while the invocation continued.", + attributes: { phase: { type: "string", required: true, description: "Committed checkpoint phase." } } + }, + "pi.durable.replay": { + description: "A nested tool call was answered from its stored result.", + attributes: { "tool.name": { type: "string", required: true, description: "Called tool name." } } + } + }, + status: { + default: "ok", + errorWhen: "Faulted, failed, and orphaned outcomes use task_faulted, task_failed, and task_orphaned with a diagnostic capped at 500 characters. Aborted outcomes keep status ok." + } + } + }, + metrics: { + "pi.durable.reports": { + kind: "counter", + description: "Reports raised, grouped by their fixed kind.", + attributes: { type: reportAttributes.type } + }, + "pi.durable.phase.duration": { + kind: "histogram", + unit: "ms", + description: "Duration of a phase invocation and its decision commit.", + attributes: { + task: { type: "string", required: true, description: "Registered task name." }, + phase: { type: "string", required: true, description: "Invoked checkpoint phase." }, + outcome: { type: "string", required: true, description: "Phase outcome." } + } + }, + "pi.durable.tasks.active": { + kind: "upDownCounter", + description: "Live tasks held by this Harness; decremented at terminal settlement or close.", + attributes: { task: { type: "string", required: true, description: "Registered task name." } } + } + } +}); + +// node_modules/@earendil-works/pi-durable/dist/harness/util.js +var Waiters = class { + #sets = /* @__PURE__ */ new Map(); + add(key, context) { + const signal = context.abortSignal; + if (signal?.aborted) + return Promise.reject(signal.reason); + const waiter = Promise.withResolvers(); + const set = this.#sets.get(key) ?? /* @__PURE__ */ new Set(); + this.#sets.set(key, set.add(waiter)); + if (signal !== void 0) { + const onAbort = () => { + set.delete(waiter); + if (set.size === 0 && this.#sets.get(key) === set) + this.#sets.delete(key); + waiter.reject(signal.reason); + }; + signal.addEventListener("abort", onAbort, { once: true }); + const detach = () => signal.removeEventListener("abort", onAbort); + waiter.promise.then(detach, detach); + } + return waiter.promise; + } + keys() { + return [...this.#sets.keys()]; + } + resolve(key, value2) { + const set = this.#sets.get(key); + this.#sets.delete(key); + for (const waiter of set ?? []) + waiter.resolve(value2); + } + rejectAll(error) { + const sets = [...this.#sets.values()]; + this.#sets.clear(); + for (const set of sets) + for (const waiter of set) + waiter.reject(error); + } +}; +async function scanAll(scan) { + const items = []; + let cursor; + do { + const page2 = await scan(cursor); + items.push(...page2.items); + cursor = page2.next; + } while (cursor !== void 0); + return items; +} +function closedError(session) { + const failure = session.failure; + return failure === void 0 ? new Error("Harness is closed") : new SessionFailed(failure.error); +} +function optionalExtension(extension) { + return extension === void 0 ? {} : { extension }; +} +function conversationEntries(conversationId, query) { + return { + conversationId, + ...query.minEntryId === void 0 ? {} : { minEntryId: query.minEntryId }, + ...query.maxEntryId === void 0 ? {} : { maxEntryId: query.maxEntryId }, + ...query.order === void 0 ? {} : { order: query.order } + }; +} + +// node_modules/@earendil-works/pi-durable/dist/harness/scheduler.js +var SCAN_PAGE_SIZE3 = 256; +var NO_KEYS2 = []; +var LIVE_STATUSES = ["pending", "running", "waiting", "sleeping", "completing"]; +function blockedSubject(record) { + return { + id: record.id, + kind: record.kind, + version: record.version, + abortRequested: record.abortRequested, + ...record.abortReason === void 0 ? {} : { abortReason: record.abortReason }, + status: record.state.status + }; +} +var CONTINUE = { kind: "continue" }; +var PROGRESS = { kind: "progress" }; +var END = { kind: "end" }; +var CASCADE = { kind: "cascade" }; +function conversationNode(id) { + return `c${id}`; +} +function conversationOf(node) { + return Number(node.slice(1)); +} +function parentNode(node) { + return node.owner ?? conversationNode(node.conversationId); +} +var TaskScheduler = class { + #telemetry; + #activeMetric; + #durationMetric; + #resumed = /* @__PURE__ */ new Set(); + #session; + #storage; + #registry; + #models; + #agent; + #settings; + #env; + #now; + #onWake; + #timers; + #writeAtClose; + #report; + #settleOutcome; + #limitsRestarts; + #withdrawInputs; + #conversation; + #context; + #live = /* @__PURE__ */ new Map(); + /** + * Context range last read through a task runtime, per conversation: a later read, by any of its tasks, scans only + * newer entries. `idleSince` is the Harness time it was first seen idle. Derived and never persisted; dropped at the + * first idle check after `settings.contextRetentionMs` of idleness, and at close. + */ + #contexts = /* @__PURE__ */ new Map(); + /** + * The idle kept contexts by `idleSince`, oldest first: the expiry order, so neither an expiry nor finding the next one + * scans `#contexts`. Kept sorted also when the Harness clock goes back (see `#markIdle`). + */ + #idleOrder = /* @__PURE__ */ new Map(); + /** At least the newest `idleSince` in `#idleOrder` (drops do not lower it): an older one added means the clock went back. */ + #idleNewest = Number.NEGATIVE_INFINITY; + /** + * A chain load resolved what `#idle()` treats as unknown for a live task whose chain is not loaded, which can make a + * scope idle without a task change below it; the next idle check then covers every scope. + */ + #unknownsChanged = false; + /** Idle checks that covered every scope (`idleState`, a test diagnostic). */ + #fullIdleChecks = 0; + /** Background timer for the earliest expiry of an idle context, unless the host declined it (see `#scheduleExpiry`). */ + #expiry; + #invocations = /* @__PURE__ */ new Map(); + #taskWaiters = new Waiters(); + /** Idle waiters by conversation; `undefined` waits for the whole Harness. */ + #idleWaiters = new Waiters(); + /** Definition whose migration failed per task; retried only once the registry resolves another definition. */ + #failedMigrations = /* @__PURE__ */ new Map(); + /** Owner task of each known conversation, `null` when ownerless. */ + #edges = /* @__PURE__ */ new Map(); + /** Ownership fields of the known terminal tasks, which walks pass through. */ + #settled = /* @__PURE__ */ new Map(); + /** + * Ended tasks and conversations found unneeded, dropped by `#sweep()` at the end of the commit's publication unless + * needed again by then: a chain load installs nodes before the work below them is listed. + */ + #dropQueue = /* @__PURE__ */ new Set(); + /** + * The tree downward around live work: each node's child nodes that are live tasks or have nodes listed below them. + * A conversation's parent is its owner task; ownerless ones with work are in `#roots`. + */ + #below = /* @__PURE__ */ new Map(); + #roots = /* @__PURE__ */ new Set(); + /** Known tasks whose chain may not be loaded; every other known task's chain is, and stays, loaded. */ + #unloaded = /* @__PURE__ */ new Set(); + /** Live tasks with cancellation intent, the sources of abort cascades (spec §5.4). */ + #intent = /* @__PURE__ */ new Set(); + /** Live tasks that are not `completing`, the candidates of a reservation pass; ones found waiting leave it. */ + #runnable = /* @__PURE__ */ new Set(); + /** `completing` tasks the next finalize pass checks: those that started holding, and holders of ended work. */ + #finalizeChecks = /* @__PURE__ */ new Set(); + /** Live waiting tasks by each task in their `on`. */ + #waiters = /* @__PURE__ */ new Map(); + /** + * `failFast` waiters the next reconcile checks for a failed task in `on`: at open, when they start waiting, and when + * one of their tasks fails. + */ + #failFastChecks = /* @__PURE__ */ new Set(); + /** + * Live tasks with `abandonOnRestart` found at open, from an earlier Harness. The first reservation pass abort-marks + * them with reason `restart`, so nothing of them or below them runs a phase again. + */ + #abandoned = /* @__PURE__ */ new Set(); + /** Sleeping live tasks, due or not: the candidates of `#wakeDue()`. */ + #sleeping = /* @__PURE__ */ new Set(); + /** Timer for the earliest sleep, without `onWake` while scheduling runs. */ + #timer; + /** Last value given to `onWake`, so an unchanged one is not repeated. */ + #lastWake; + #wakeScheduled = false; + #blockedListeners = /* @__PURE__ */ new Set(); + /** A registry snapshot that threw for the task graph was reported; it is read per record, so only once. */ + #snapshotReported = false; + #reconcileScheduled = false; + /** Reconcile passes underway with work (they may overlap): their commits finalize held outcomes and mark cascades. */ + #reconcilingWork = 0; + #sweepScheduled = false; + /** + * Nodes chain loads installed for jobs whose commits are not published yet, with how many such jobs: the sweep keeps + * them, as work a pending commit creates below them needs them. + */ + #pins = /* @__PURE__ */ new Map(); + /** Keys the decision region underway reads (`#region()`); set only while one runs. */ + #reading; + #cascadePending = false; + #unsubscribeRegistry = () => { + }; + #enabled = false; + #readOnly; + #closing = false; + #dirty = false; + #draining = false; + constructor(options) { + this.#telemetry = options.telemetry ?? NOOP_TELEMETRY_CONTEXT; + const metrics = createTypedMetrics(this.#telemetry.metrics ?? NOOP_TELEMETRY_METRICS, [DURABLE_TELEMETRY_SCHEMA]); + this.#activeMetric = metrics.upDownCounter("pi.durable.tasks.active"); + this.#durationMetric = metrics.histogram("pi.durable.phase.duration"); + this.#session = options.session; + this.#storage = options.storage; + this.#registry = options.registry; + this.#models = options.models; + this.#agent = options.agent; + this.#settings = options.settings; + this.#env = options.env; + this.#now = options.now; + this.#onWake = options.onWake; + this.#timers = options.timers; + this.#writeAtClose = options.writeAtClose; + this.#report = options.report; + this.#settleOutcome = options.settleOutcome; + this.#limitsRestarts = options.limitsRestarts; + this.#withdrawInputs = options.withdrawInputs; + this.#conversation = options.conversation; + this.#context = options.context; + this.#readOnly = options.readOnly === true; + } + /** + * Load live tasks and change surviving `running` tasks back to `pending`, counting the restart. Dispatches nothing; + * a task cut off `settings.restartLimit` times ends when it is next reserved. Read-only, it only loads them: a + * `running` task stays as committed, running in another process. + */ + async open(context) { + this.#session.followCommits((publication) => this.#observe(publication)); + this.#session.subscribeClose(() => this.#seal()); + this.#unsubscribeRegistry = this.#registry.subscribe(() => { + this.#notifyBlocked(); + this.#kick(); + }); + await this.#session.commitWith(async (tx) => { + await this.#published(); + const scans = []; + for (const status of LIVE_STATUSES) { + scans.push(await scanAll((cursor) => tx.scanTasks({ status }, SCAN_PAGE_SIZE3, cursor))); + } + for (const records of scans) { + for (const record of records) { + this.#track(void 0, record); + this.#resumed.add(record.id); + if (this.#readOnly) + continue; + if (record.abandonOnRestart === true) + this.#abandoned.add(record.id); + if (record.state.status === "running") { + const restarts = (record.restarts ?? 0) + 1; + const pending = withState(record, { status: "pending", checkpoint: record.state.checkpoint }); + tx.setTask({ ...pending, restarts }); + } + if (record.state.status === "waiting" && record.state.policy === "failFast") { + this.#failFastChecks.add(record.id); + } + } + } + }, context); + if (this.#readOnly) + return; + this.#cascadePending = true; + this.#scheduleReconcile(); + this.#scheduleWake(); + } + /** + * Enable scheduling, and make sleeping tasks that are due runnable: a host wakeup, such as an alarm, calls this. + * Idempotent; the kick does nothing once closing. + */ + resume() { + if (this.#readOnly) + throw new ReadOnlySession("running tasks"); + this.#enabled = true; + this.#wakeDue(); + this.#kick(); + } + /** + * Why a live task cannot run here, if it cannot: its definition is missing, too old, or failed to migrate. A running + * task, an abort-marked one, and one holding its outcome are never blocked. + */ + blockedReason(record) { + const status = record.status; + if (status === "running" || status === "completing" || status === "terminal") + return void 0; + if (record.abortRequested && record.abortReason === void 0) + return void 0; + let snapshot; + try { + snapshot = this.#registry.snapshot(); + } catch (error) { + if (!this.#snapshotReported) + this.#report(error, REGISTRY); + this.#snapshotReported = true; + return void 0; + } + const fit = this.#fit(record, snapshot.task(record.kind)); + if ("reason" in fit) + return fit.reason; + return fit.migrates && fit.task.definition.migrate === void 0 ? "migration_failed" : void 0; + } + /** Call `listener` when blocked reasons may have changed without a commit: a registry change or a failed migration. */ + subscribeBlocked(listener) { + this.#blockedListeners.add(listener); + return () => this.#blockedListeners.delete(listener); + } + /** + * When the Session next needs a process: `active` while some task can run now or is running, `at` for the earliest + * sleep not yet due. Synchronous, from memory; a task whose chain is not loaded yet counts as it would alone. + */ + wake() { + if (this.#readOnly) + return { active: false }; + const now = this.#now(); + const active = this.#invocations.size > 0 || this.#reconcilingWork > 0 || this.#reconcileWork() || this.#runsNow(now); + let at; + for (const id of this.#sleeping) { + const record = this.#live.get(id); + const state = record?.state; + if (state?.status === "sleeping" && !record.abortRequested && state.until > now) { + at = at === void 0 ? state.until : Math.min(at, state.until); + } + } + return at === void 0 ? { active } : { active, at }; + } + /** Whether a live task can run now: the scan `wake()` needs only while no invocation runs. */ + #runsNow(now) { + let snapshot; + let snapshotFailed = false; + for (const record of this.#live.values()) { + const state = record.state; + if (state.status === "completing") + continue; + if (state.status === "waiting" && !record.abortRequested && state.on.some((id) => this.#live.has(id))) + continue; + if (state.status === "sleeping" && !record.abortRequested && state.until > now) + continue; + if (record.abortRequested && this.#waitingOn(record, true).length > 0) + continue; + if (!record.abortRequested || record.abortReason !== void 0) { + if (snapshot === void 0 && !snapshotFailed) { + try { + snapshot = this.#registry.snapshot(); + } catch (error) { + snapshotFailed = true; + this.#report(error, REGISTRY); + } + } + if (snapshot !== void 0 && "reason" in this.#fit(record, snapshot.task(record.kind))) + continue; + } + return true; + } + return false; + } + /** + * Signal every invocation and wait for them, then write the tasks they ran back as `pending` (`writeAtClose`), as a + * close is not a crash. Close calls this after every close listener has run, so waits, watches, and streams a task + * holds end with the Session's reason, not as cancelled by its signal. + */ + async join() { + const stopped = [...this.#invocations.values()]; + for (const invocation of stopped) + invocation.controller.abort(); + await Promise.allSettled(stopped.map((invocation) => invocation.done)); + if (stopped.length === 0) + return; + await this.#writeAtClose(() => stopped.flatMap((invocation) => { + const record = this.#live.get(invocation.taskId); + if (record?.state.status !== "running") + return []; + const value2 = withState(record, { status: "pending", checkpoint: record.state.checkpoint }); + return [{ type: "task", value: value2 }]; + })).catch(() => { + }); + } + /** + * Commit the abort mark, or settle a task that no registered definition can take as `orphaned` when nothing it owns + * is live, then join the run invocation seen on the line; the commit listener signalled it. The abort invocation + * starts once the task's ordinary owned work is gone. A `completing` task is only marked. A request replaces a + * `restart` mark, so a task abandoned after a restart that waits for its definition is orphaned; with `keepRestart`, + * as for an owner's own cleanup, such a task keeps its mark and waits on. + */ + async abort(id, context, keepRestart = false) { + const marked = await this.#session.commitWith(async (tx) => { + const current = await tx.task(id); + if (current === void 0) + throw new Error(`Task ${id} does not exist`); + if (current.state.status === "terminal") + return { result: "terminal" }; + const invocation = this.#invocations.get(id); + if (keepRestart && current.abortReason === "restart") + return { result: "marked" }; + if (invocation === void 0 && current.state.status !== "completing") { + await this.#loadScopes(false); + const owns = await this.#region(() => this.#hasOwnedLive(id), this.#reloadScopes); + const resolution = owns ? void 0 : this.#resolve(current, this.#registry.snapshot()); + if (resolution?.kind === "blocked") { + await this.#terminate(tx, current, { status: "orphaned", reason: resolution.reason }); + return { result: "marked" }; + } + } + if (!current.abortRequested || current.abortReason !== void 0) + tx.setTask(withAbortMark(current)); + return { result: "marked", run: invocation?.mode === "run" ? invocation : void 0 }; + }, context); + if (marked.run !== void 0) { + await awaitWithContext(Promise.race([marked.run.done, this.#session.failed]), context); + } + return marked.result; + } + async waitForTask(id, context) { + const found = await this.#session.readOnLine(async (storage) => { + if (this.#closing) + throw closedError(this.#session); + if (await this.#region(() => this.#liveRecord(id) !== void 0)) { + return { promise: this.#taskWaiters.add(id, context) }; + } + const record = await storage.task(id, context); + if (record === void 0) + throw new Error(`Task ${id} does not exist`); + return { promise: Promise.resolve(record) }; + }); + return found.promise; + } + /** + * Resolve when ordinary traversal from the conversation, or from every ownerless conversation, reaches no live + * non-background task. + */ + waitForIdle(conversationId, context) { + if (this.#closing) + return Promise.reject(closedError(this.#session)); + if (this.#idle(conversationId)) + return Promise.resolve(); + this.#scheduleReconcile(); + return this.#idleWaiters.add(conversationId, context); + } + /** + * `Conversation.abort()`: in one commit, withdraw the queued inputs and mark every live non-background task that + * ordinary traversal from the conversation reaches; resolves once the scope is idle. With `background`, traversal + * crosses background boundaries, and the wait also covers every task it reached. + */ + async abortConversation(conversationId, background, context) { + const reached = await this.#session.commitWith(async (tx) => { + await this.#published(); + const queued = await this.#loadScopes(true); + const scope = { conversation: conversationId }; + const reached2 = []; + const walk = this.#walkDown(conversationNode(conversationId), { crossBackground: background }); + for (const { node, live } of walk) { + if (live === void 0 || node.background && !background) + continue; + reached2.push(live.id); + if (!live.abortRequested || live.abortReason !== void 0) + tx.setTask(withAbortMark(live)); + } + for (const id of queued) { + if (this.#inScope({ conversation: id }, scope, background) === true) + await this.#withdrawInputs(tx, id); + } + return reached2; + }, context); + if (background) + for (const id of reached) + await this.waitForTask(id, context); + await this.waitForIdle(conversationId, context); + } + /** + * The ownership memberships a commit's task and conversation changes write (group commit §4.2), at its admission on + * the line: for each task created or made terminal, every node from its parent up to and including the nearest live + * task, or the root conversation, and then the roots too, conservatively, as a pending end may unlist the root a + * creation finds listed; for each conversation created under a task, that task; and the intent set when + * a change sets, upgrades, or clears a mark or a held or ended outcome other than `completed`. Loads the chains it + * walks; the nodes it installs stay until the commit is published. + */ + membershipKeys(tx) { + const tasks = tx.stagedTasks(); + const conversations = tx.stagedConversations(); + if (tasks.length === 0 && conversations.every((record) => record.owner === void 0)) + return NO_KEYS2; + return this.#membershipKeys(tx, tasks, conversations); + } + async #membershipKeys(tx, tasks, conversations) { + const keys = /* @__PURE__ */ new Set(); + const overlay = overlayOf(tx); + const created = new Set(tx.createdTaskIds()); + const reached = /* @__PURE__ */ new Map(); + for (const record of tasks) { + if (intentChanges(this.#live.get(record.id), record)) + keys.add(INTENT_KEY); + if (!created.has(record.id) && record.state.status !== "terminal") + continue; + await this.#loadChain(parentOf(record), overlay); + if (await this.#chainKeys(parentNode(record), overlay, keys, reached) !== void 0) + keys.add(ROOTS_KEY); + } + for (const conversation of conversations) { + const owner = conversation.owner?.taskId; + if (owner === void 0) + continue; + await this.#loadChain({ task: owner }, overlay); + await this.#chainKeys(owner, overlay, keys, reached); + } + return [...keys]; + } + /** + * Add the memberships from `start` up to and including the nearest live task, or the root conversation, which it + * returns. `reached` keeps, per node walked, where its walk ended, so a chain several tasks of a commit share is + * walked once. Whether an ancestor is live can change under a pending commit, so it is read after a touch of the + * ancestor's record: a pending end must not stop the chain early. Ownership fields are immutable, so not keyed. + */ + async #chainKeys(start, overlay, keys, reached) { + const walked = []; + let root2; + let node = start; + while (node !== void 0 && node !== null) { + const key = ownedKey(node); + if (reached.has(key)) { + root2 = reached.get(key); + break; + } + keys.add(key); + walked.push(key); + if (typeof node === "string") { + const conversation = conversationOf(node); + node = this.#edge(conversation, overlay); + if (node === null) + root2 = conversation; + continue; + } + let record = overlay.tasks.get(node); + if (record === void 0) { + const gate = this.#session.touch(taskKey(node)); + if (gate !== void 0) { + await gate; + await this.#loadChain({ task: node }, overlay); + } + record = this.#live.get(node); + } + if (record !== void 0 && record.state.status !== "terminal") + break; + const above = record ?? this.#settled.get(node); + node = above === void 0 ? void 0 : parentNode(above); + } + for (const key of walked) + reached.set(key, root2); + return root2; + } + // ─── Scheduling ──────────────────────────────────────────────────────── + #observe(publication) { + if (publication.kind === "memory") + return; + this.#advanceContexts(publication); + const updated = []; + const failed = []; + let changed = false; + let dirty = /* @__PURE__ */ new Set(); + for (const change of publication.changes) { + if (change.type === "conversation" && !this.#edges.has(change.value.id)) { + this.#setEdge(change.value.id, change.value.owner?.taskId ?? null); + } + } + for (const change of publication.changes) { + if (change.type !== "task") + continue; + changed = true; + const record = change.value; + const previous = this.#live.get(record.id); + if (failedOutcome(record) && (previous === void 0 || !failedOutcome(previous))) + failed.push(record.id); + this.#track(previous, record); + const liveness = previous === void 0 || record.state.status === "terminal"; + if (liveness && dirty !== void 0 && !this.#addScopesAbove(record, dirty)) + dirty = void 0; + if (record.state.status === "terminal") { + this.#failedMigrations.delete(record.id); + this.#failFastChecks.delete(record.id); + this.#taskWaiters.resolve(record.id, record); + this.#scheduleReconcile(); + continue; + } + if (record.abortRequested && previous?.abortRequested !== true) { + this.#cascadePending = true; + const invocation = this.#invocations.get(record.id); + if (invocation?.mode === "run") + queueMicrotask(() => invocation.controller.abort()); + } + if (previous?.abortReason !== void 0 && record.abortReason === void 0) + this.#cascadePending = true; + const status = record.state.status; + if (status === "completing" && previous?.state.status !== "completing") { + if (cancellationIntent(record)) + this.#cascadePending = true; + this.#scheduleReconcile(); + } + if (status === "waiting" && record.state.policy === "failFast" && previous?.state.status !== "waiting") { + this.#failFastChecks.add(record.id); + this.#scheduleReconcile(); + } + if (previous === void 0) + updated.push(record); + } + for (const id of failed) { + for (const waiter of this.#waiters.get(id) ?? []) { + const state = this.#live.get(waiter)?.state; + if (state?.status === "waiting" && state.policy === "failFast") { + this.#failFastChecks.add(waiter); + this.#scheduleReconcile(); + } + } + } + for (const change of publication.changes) { + if (change.type !== "submission" || change.value.status !== "queued" || change.value.type !== "input") + continue; + if (this.#intent.size === 0) + continue; + const conversation = change.value.conversationId; + if (!this.#known(conversationNode(conversation)) || this.#belowCancelled({ conversation })) { + this.#cascadePending = true; + } + } + for (const record of updated) { + if (this.#unloaded.has(record.id)) + this.#scheduleReconcile(); + else if (!record.background && !record.abortRequested && this.#belowCancelled(parentOf(record))) { + this.#cascadePending = true; + } + } + if (this.#cascadePending) + this.#scheduleReconcile(); + this.#sweep(); + if (!changed) + return; + this.#settleIdle(dirty); + this.#kick(); + } + /** + * Add the conversations above `record` to `scopes`: those whose idleness a change of it can change. False when a node + * on the way up is not known. A conversation already in `scopes` has everything above it there too. + */ + #addScopesAbove(record, scopes) { + for (const step of this.#above(parentOf(record))) { + if ("unknown" in step) + return false; + if (!("conversation" in step)) + continue; + if (scopes.has(step.conversation)) + return true; + scopes.add(step.conversation); + } + return true; + } + /** + * Extend each kept context range with the entries a stored commit appended to its conversation, so a later read + * needs no Storage scan. Entries are published in ID order. + */ + #advanceContexts(publication) { + if (this.#contexts.size === 0) + return; + let appended; + for (const change of publication.changes) { + if (change.type !== "entry" || !this.#contexts.has(change.value.conversationId)) + continue; + appended ??= /* @__PURE__ */ new Map(); + const entries2 = appended.get(change.value.conversationId); + if (entries2 === void 0) + appended.set(change.value.conversationId, [change.value]); + else + entries2.push(change.value); + } + if (appended === void 0) + return; + for (const [conversationId, entries2] of appended) { + const kept = this.#contexts.get(conversationId); + if (kept.idleSince !== void 0 && kept.expiresAt !== void 0 && kept.expiresAt <= this.#now()) { + this.#dropContext(conversationId); + continue; + } + const range = advanceRange(kept.range, entries2); + if (range === void 0) + this.#dropContext(conversationId); + else + kept.range = range; + } + } + /** + * `settings.contextRetentionMs`, or 0 when the host's settings throw. Kept contexts are only a cache, so dropping them + * is safe, while a throw here would escape commit listeners, reconciliation, and the expiry timer. + */ + #contextRetentionMs() { + try { + return this.#settings().contextRetentionMs; + } catch (error) { + this.#report(error, SETTINGS); + return 0; + } + } + /** + * After task changes below the conversations in `scopes` (every conversation when undefined): resolve their idle + * waiters and the Harness-wide ones, drop the kept contexts whose idle period passed the retention, then start or end + * the idle periods of the kept contexts in `scopes`. A task change can change the idleness only of the conversations + * above it, so no check visits every conversation. + */ + #settleIdle(scopes) { + const all = scopes === void 0 || this.#unknownsChanged; + this.#unknownsChanged = false; + if (all) + this.#fullIdleChecks++; + this.#resolveIdleWaiters(all ? void 0 : scopes); + const now = this.#now(); + const retention = this.#contextRetentionMs(); + this.#expireContexts(now, retention); + for (const conversationId of all ? [...this.#contexts.keys()] : scopes) { + const kept = this.#contexts.get(conversationId); + if (kept === void 0) + continue; + if (!this.#idle(conversationId)) { + if (kept.idleSince === void 0) + continue; + kept.idleSince = void 0; + this.#idleOrder.delete(conversationId); + } else if (retention <= 0) { + this.#dropContext(conversationId); + } else if (kept.idleSince === void 0) { + kept.idleSince = now; + kept.expiresAt = now + retention; + this.#markIdle(conversationId, now); + } + } + this.#scheduleExpiry(); + } + /** Resolve the idle waiters of the conversations in `scopes` (all when undefined) and the Harness-wide ones. */ + #resolveIdleWaiters(scopes) { + for (const conversationId of this.#idleWaiters.keys()) { + if (conversationId !== void 0 && scopes !== void 0 && !scopes.has(conversationId)) + continue; + if (this.#idle(conversationId)) + this.#idleWaiters.resolve(conversationId); + } + } + /** + * Drop the kept contexts idle for at least `retention`, oldest first, with the retention setting of now; with no + * retention, every idle one, also those whose idle period a clock that went back makes start after now. + */ + #expireContexts(now, retention) { + for (const [conversationId, idleSince] of this.#idleOrder) { + if (retention > 0 && now - idleSince < retention) + return; + this.#dropContext(conversationId); + } + } + /** + * Start the idle period of a kept context in the expiry order. An idle period older than the newest one kept, which + * a clock that went back starts, sorts the order again, and the newest is taken from what is kept then. + */ + #markIdle(conversationId, idleSince) { + this.#idleOrder.delete(conversationId); + this.#idleOrder.set(conversationId, idleSince); + if (this.#idleOrder.size === 1 || idleSince >= this.#idleNewest) { + this.#idleNewest = idleSince; + return; + } + const sorted = [...this.#idleOrder].sort((a, b) => a[1] - b[1]); + this.#idleOrder.clear(); + for (const [id, since] of sorted) + this.#idleOrder.set(id, since); + this.#idleNewest = sorted.at(-1)[1]; + } + /** Forget a kept context, idle or not, and its place in the expiry order. */ + #dropContext(conversationId) { + this.#contexts.delete(conversationId); + this.#idleOrder.delete(conversationId); + } + /** + * Drop the expired contexts when the earliest idle context expires, on a background timer, which never keeps the + * process alive. Where the host declines it, as the default does in Cloudflare Workers, none is kept: a pending timer + * could keep a Durable Object from being evicted, and eviction frees the contexts. There, task changes alone check + * expiry. + */ + #scheduleExpiry() { + const oldest = this.#idleOrder.values().next(); + const at = oldest.done === true ? void 0 : oldest.value + this.#contextRetentionMs(); + if (this.#expiry !== void 0 && this.#expiry.at === at) + return; + this.#expiry?.disarm(); + this.#expiry = void 0; + if (at === void 0 || this.#closing) + return; + const disarm = this.#timers.background(() => { + this.#expiry = void 0; + this.#expireContexts(this.#now(), this.#contextRetentionMs()); + this.#scheduleExpiry(); + }, at - this.#now()); + if (disarm !== void 0) + this.#expiry = { at, disarm }; + } + // ─── Ownership ─────────────────────────────────────────────────────────── + #scheduleReconcile() { + if (this.#reconcileScheduled || this.#closing || this.#readOnly) + return; + this.#reconcileScheduled = true; + queueMicrotask(() => void this.#reconcile()); + } + /** + * One commit that applies what committed records imply: abort marks below live owners with cancellation intent + * (spec §5.4), `failFast` marks (spec §5.5), withdrawn queued inputs below cancelled owners, and the final terminal + * record of every `completing` task whose ordinary owned work is gone. The durable records are the intent, so this + * also repairs whatever a crash left unapplied. Resolves idle waiters that the loaded edges decide. + */ + async #reconcile() { + this.#reconcileScheduled = false; + const work = this.#reconcileWork(); + if (work) + this.#reconcilingWork++; + try { + await this.#session.commitInternal(async (tx) => { + if (this.#closing) + return; + const cascade = this.#cascadePending; + const queued = await this.#loadScopes(cascade); + if (cascade) + this.#cascadePending = false; + const marks = await this.#marks(); + for (const { record, reason } of marks.values()) + tx.setTask(withAbortMark(record, reason)); + const withdrawn = await this.#region(() => queued.filter((id) => this.#belowCancelled({ conversation: id })), this.#reloadScopes); + for (const id of withdrawn) + await this.#withdrawInputs(tx, id); + await this.#finalize(tx); + }, this.#context); + } catch (error) { + this.#failSession(error); + } + if (work) + this.#reconcilingWork--; + this.#scheduleWake(); + if (this.#unknownsChanged) { + this.#settleIdle(void 0); + return; + } + this.#resolveIdleWaiters(void 0); + this.#expireContexts(this.#now(), this.#contextRetentionMs()); + this.#scheduleExpiry(); + } + /** + * The abort marks committed records imply (spec §5.4, §5.5): every live foreground task below a live owner with + * cancellation intent, which is its nearest one (a walk down from each owner with intent does not enter another, + * whose own walk covers what is below it), and every other live task in the `on` of a `failFast` waiter one of whose + * tasks failed. A cascade from an abandoned owner passes its `restart` reason on; any other intent marks, or upgrades + * a `restart` mark, as a request. Collected first, so a request wins over a `restart` mark of the same pass. Derived + * again on every pass, as loading edges can reveal a cancelled owner. Takes the `failFast` checks once its decision + * stands. + */ + async #marks() { + const ended = /* @__PURE__ */ new Map(); + for (; ; ) { + const plan = await this.#region(() => this.#planMarks(ended), this.#reloadScopes); + if ("missing" in plan) { + for (const id of plan.missing) + ended.set(id, await this.#session.lineStorage.task(id, this.#context) ?? null); + continue; + } + for (const id of plan.checked) + this.#failFastChecks.delete(id); + return plan.marks; + } + } + /** `#marks()`' decision region; the `failFast` members it needs from Storage first, when `ended` lacks them. */ + #planMarks(ended) { + const marks = /* @__PURE__ */ new Map(); + const mark = (found, reason) => { + const record = this.#liveRecord(found.id); + const staged = marks.get(record.id); + if (staged !== void 0 && staged.reason === void 0) + return; + if (record.abortRequested && (record.abortReason === void 0 || reason !== void 0)) + return; + marks.set(record.id, { record, reason }); + }; + this.#record(INTENT_KEY); + for (const id of this.#intent) { + const owner = this.#liveRecord(id); + const restart = owner.abortReason === "restart" && !failedOutcome(owner); + for (const { node, live } of this.#walkDown(id, { enter: (below) => !this.#intent.has(below) })) { + if (live !== void 0 && !node.background) + mark(live, restart ? "restart" : void 0); + } + } + const checked = [...this.#failFastChecks]; + const missing = []; + for (const id of checked) { + const waiter = this.#liveRecord(id); + if (waiter?.state.status !== "waiting") + continue; + let failed = false; + for (const member of waiter.state.on) { + const record = this.#liveRecord(member) ?? ended.get(member); + if (record === void 0) + missing.push(member); + else if (record !== null && failedOutcome(record)) + failed = true; + } + if (!failed) + continue; + for (const member of waiter.state.on) { + const record = this.#liveRecord(member); + if (record !== void 0 && !failedOutcome(record)) + mark(record, void 0); + } + } + return missing.length > 0 ? { missing } : { marks, checked }; + } + /** Whether a reconcile pass would have work: a cascade to derive, held outcomes to check, or `failFast` waits. */ + #reconcileWork() { + return this.#cascadePending || this.#finalizeChecks.size > 0 || this.#failFastChecks.size > 0; + } + /** + * Write the terminal record of every `completing` task without live ordinary owned work. Finalizing one can free its + * owner, so this repeats over the commit's candidates until nothing changes. A held scheduler outcome gets its + * Harness cleanup here. In rounds, one decision region each: the holders the tasks of one round free are checked once, + * in the next, so a holder of many tasks that end together is walked once, not once per task. The first round takes + * the `completing` tasks to check once its decision stands. + */ + async #finalize(tx) { + const done = /* @__PURE__ */ new Set(); + const overlay = overlayOf(tx); + let round; + for (; ; ) { + const ids = round; + const plan = await this.#region(() => this.#planRound(ids ?? [...this.#finalizeChecks], overlay, done), this.#reloadScopes); + if (ids === void 0) + this.#finalizeChecks.clear(); + for (const { record, terminal } of plan.finalized) { + tx.setTask(terminal); + overlay.tasks.set(record.id, terminal); + done.add(record.id); + const outcome = record.state.outcome; + if (outcome.status === "faulted" || outcome.status === "orphaned") { + await this.#settleOutcome(tx, record, outcome); + } + } + if (plan.next.length === 0) + return; + round = plan.next; + } + } + /** + * One finalize round's decision: which of `ids` are `completing` without live ordinary owned work below them, in the + * commit's candidates with the round's own finalizations applied in order, and the holders above them to check next. + * Tasks finalized have no live work below them, so walks down skip them. It applies the round's terminal records to + * `overlay` while it decides and takes them back before it returns, so a run again starts from the same candidates. + */ + #planRound(ids, overlay, finalized) { + const tasks = overlay.tasks; + const round = /* @__PURE__ */ new Set(); + const done = { has: (id) => round.has(id) || finalized.has(id) }; + const ended = []; + const next = /* @__PURE__ */ new Set(); + try { + for (const id of ids) { + const staged = tasks.get(id); + const record = staged ?? this.#liveRecord(id); + if (record?.state.status !== "completing" || done.has(id)) + continue; + if (this.#hasOwnedLive(id, overlay, done)) + continue; + const terminal = withState(record, { status: "terminal", outcome: record.state.outcome }); + tasks.set(id, terminal); + round.add(id); + ended.push({ record, terminal, staged: staged !== void 0 }); + const above = this.#nearestLiveAbove(record, overlay); + if (above?.state.status === "completing") + next.add(above.id); + } + } finally { + for (const { record, staged } of ended) { + if (staged) + tasks.set(record.id, record); + else + tasks.delete(record.id); + } + } + return { finalized: ended, next: [...next] }; + } + /** + * Load the owner chains of the tasks in `#unloaded` and, with `queued`, of every conversation with queued inputs, + * on the Session line; returns the latter. Reads through the line's Storage, so it may run inside a commit callback. + */ + async #loadScopes(queued) { + for (const id of [...this.#unloaded]) { + if (this.#unloaded.has(id)) + await this.#loadChain({ task: id }); + } + if (!queued) + return []; + const submissions = await scanAll((cursor) => this.#session.lineStorage.scanSubmissions({ status: "queued" }, SCAN_PAGE_SIZE3, cursor, this.#context)); + const inputs = submissions.filter((submission2) => submission2.type === "input"); + const conversations = [...new Set(inputs.map((submission2) => submission2.conversationId))]; + for (const id of conversations) + await this.#loadChain({ conversation: id }); + return conversations; + } + /** + * Load the owner edges and task nodes from `start` up to its ownerless root. A known task outside `#unloaded` ends the + * walk, as its chain is loaded; the `#unloaded` tasks passed have a loaded chain afterwards. Loading a node can reveal + * a cancelled owner, so it makes the next reconcile derive cascade marks. The nodes it installs stay until the job's + * commit is published (`#pin()`). + */ + async #loadChain(start, overlay) { + const passed = []; + let installed = false; + let at = start; + try { + while (at !== void 0) { + if ("task" in at) { + const id = at.task; + let node = this.#live.get(id) ?? this.#settled.get(id); + if (node === void 0 && overlay?.tasks.has(id) === true) + break; + if (node !== void 0 && !this.#unloaded.has(id)) + break; + if (node === void 0) { + const record = await this.#session.lineStorage.task(id, this.#context); + if (record === void 0) + return; + node = nodeOf(record); + if (record.state.status === "terminal") { + this.#settle(id, node); + this.#pin(id); + installed = true; + } + this.#scheduleReconcile(); + } + passed.push(id); + at = parentOf(node); + } else { + let edge = this.#edge(at.conversation, overlay); + if (edge === void 0) { + const record = await this.#session.lineStorage.conversation(at.conversation, this.#context); + edge = record?.owner?.taskId ?? null; + this.#setEdge(at.conversation, edge); + this.#pin(conversationNode(at.conversation)); + installed = true; + this.#scheduleReconcile(); + } + at = edge === null ? void 0 : { task: edge }; + } + } + } finally { + if (passed.some((id) => this.#live.has(id)) || installed && this.#liveUnloaded()) { + this.#unknownsChanged = true; + this.#scheduleReconcile(); + } + } + for (const id of passed) + this.#unloaded.delete(id); + } + /** Whether a live task's chain is not loaded yet: one `#idle()` counts as inside every scope it may be in. */ + #liveUnloaded() { + for (const id of this.#unloaded) + if (this.#live.has(id)) + return true; + return false; + } + #setEdge(conversationId, owner) { + this.#edges.set(conversationId, owner); + this.#relist(conversationNode(conversationId)); + this.#dropIfUnneeded(conversationNode(conversationId)); + } + /** Know a terminal task a chain load read, so walks pass through it; its own chain is not loaded yet. */ + #settle(id, node) { + this.#settled.set(id, node); + this.#unloaded.add(id); + this.#relist(id); + this.#dropIfUnneeded(id); + } + /** Queue an ended task or a conversation for the sweep when nothing is listed below it. */ + #dropIfUnneeded(node) { + if (typeof node !== "string" && this.#live.has(node)) + return; + if (this.#below.has(node)) + return; + this.#dropQueue.add(node); + this.#scheduleSweep(); + } + /** + * Sweep in a job of its own on the Session line, after the operation underway: a rejected commit, one with nothing to + * write, and a read publish nothing, so the sweep at the end of `#observe` would not run for what they loaded. + */ + #scheduleSweep() { + if (this.#sweepScheduled || this.#closing) + return; + this.#sweepScheduled = true; + this.#session.readOnLine(async () => { + this.#sweepScheduled = false; + this.#sweep(); + }).catch(() => { + }); + } + /** + * Drop the queued nodes that are still unneeded: not live, nothing listed below. Runs once a publication is fully + * tracked, and as a job of its own on the line, never inside an operation: work a commit creates below a chain its + * own callback loaded keeps that chain. A flat loop: unlisting already queued every node on the way up that lost its + * last listed node. + */ + #sweep() { + for (const node of this.#dropQueue) { + if (this.#below.has(node) || this.#pins.has(node)) + continue; + if (typeof node === "string") { + this.#edges.delete(conversationOf(node)); + this.#roots.delete(conversationOf(node)); + } else if (!this.#live.has(node)) { + this.#settled.delete(node); + this.#unloaded.delete(node); + } + } + this.#dropQueue.clear(); + } + /** + * Run `decide`, a decision region (group commit §6): synchronous, reading scheduler memory and recording the keys it + * reads, staging nothing and changing no scheduler state. When a key it read has an unpublished writer, its result, + * or its error, is dropped: once that writer is published, `refresh` reloads what the region needs and it runs + * again. A waiting job holds the line, so unpublished writes only shrink, and the runs converge. What a region read + * that had no unpublished writer gets none for the rest of the job, so its result stands while the job applies it. + */ + async #region(decide, refresh) { + for (; ; ) { + const keys = /* @__PURE__ */ new Set(); + this.#reading = keys; + let result; + try { + result = { value: decide() }; + } catch (error) { + result = { error }; + } finally { + this.#reading = void 0; + } + const gates = []; + for (const key of keys) { + const gate = this.#session.touch(key); + if (gate !== void 0) + gates.push(gate); + } + if (gates.length === 0) { + if ("error" in result) + throw result.error; + return result.value; + } + await Promise.all(gates); + await refresh?.(); + } + } + /** Load the chains a region walks, again after it waited: what was published meanwhile may list new work. */ + #reloadScopes = () => this.#loadScopes(false); + /** In a decision region, note that it reads `key`; anywhere else, nothing. */ + #record(key) { + this.#reading?.add(key); + } + /** A live task's committed record, read by a decision region. */ + #liveRecord(id) { + this.#record(taskKey(id)); + return this.#live.get(id); + } + /** + * Keep `node`, which a chain load of the job on the line installed, until that job's commit is published or fails: + * work it creates below the node needs it, and the sweep would drop it as unneeded before then. + */ + #pin(node) { + this.#pins.set(node, (this.#pins.get(node) ?? 0) + 1); + this.#session.onJobEnd(() => { + const count = this.#pins.get(node) - 1; + if (count > 0) { + this.#pins.set(node, count); + return; + } + this.#pins.delete(node); + this.#dropIfUnneeded(node); + }); + } + /** + * Bring the scheduler's sets in line with a task's committed record. A task that ended may free the nearest live task + * above it: one holding its outcome finalizes, an abort-marked one runs its abort handler; its waiters may run. + */ + #track(previous, record) { + const id = record.id; + const invocation = this.#invocations.get(id); + if (invocation !== void 0) + invocation.record = record; + if (record.state.status === "terminal") { + if (previous !== void 0 && !this.#closing) + this.#countActive(-1, record.kind); + this.#resumed.delete(id); + } else if (previous === void 0 && !this.#closing) { + this.#countActive(1, record.kind); + } + if (previous?.state.status === "waiting") + for (const on of previous.state.on) + deleteFrom(this.#waiters, on, id); + if (record.state.status === "terminal") { + const node = nodeOf(record); + this.#live.delete(id); + this.#sleeping.delete(id); + this.#intent.delete(id); + this.#runnable.delete(id); + this.#finalizeChecks.delete(id); + this.#settled.set(id, node); + this.#release(node); + for (const waiter of this.#waiters.get(id) ?? []) + this.#runnable.add(waiter); + this.#relist(id); + this.#dropIfUnneeded(id); + return; + } + this.#live.set(id, record); + if (previous === void 0) { + if (!this.#known(parentNode(record))) + this.#unloaded.add(id); + this.#relist(id); + } + if (cancellationIntent(record)) + this.#intent.add(id); + else + this.#intent.delete(id); + if (record.state.status === "completing") { + this.#runnable.delete(id); + this.#finalizeChecks.add(id); + } else { + this.#runnable.add(id); + } + if (record.state.status === "waiting") + for (const on of record.state.on) + addTo(this.#waiters, on, id); + if (record.state.status === "sleeping") + this.#sleeping.add(id); + else + this.#sleeping.delete(id); + } + /** The nearest live task above ended ordinary work may be free now: one holding its outcome, or an aborting one. */ + #release(node, overlay) { + const above = this.#nearestLiveAbove(node, overlay); + if (above?.state.status === "completing") + this.#finalizeChecks.add(above.id); + else if (above?.abortRequested === true) + this.#runnable.add(above.id); + return above; + } + /** + * List `start` under its parent node in `#below` while it is a live task or has nodes listed below it, and unlist it + * otherwise; then its parent, as far up as that changes. So `#below` holds exactly the tree around live work; a + * parent that loses its last listed node is queued for the sweep. A loop, as ownership chains can be deeper than the + * call stack. + */ + #relist(start) { + let node = start; + for (; ; ) { + const needed = typeof node !== "string" && this.#live.has(node) || this.#below.has(node); + let parent; + if (typeof node === "string") { + parent = this.#edges.get(conversationOf(node)); + } else { + const known = this.#live.get(node) ?? this.#settled.get(node); + if (known === void 0) + return; + parent = parentNode(known); + } + if (parent === void 0) + return; + if (parent === null) { + const root2 = conversationOf(node); + if (needed) + this.#roots.add(root2); + else + this.#roots.delete(root2); + return; + } + if (this.#below.get(parent)?.has(node) === true === needed) + return; + if (needed) { + const first = !this.#below.has(parent); + addTo(this.#below, parent, node); + if (!first) + return; + } else { + deleteFrom(this.#below, parent, node); + if (this.#below.has(parent)) + return; + this.#dropIfUnneeded(parent); + } + node = parent; + } + } + /** + * The nearest live task above ended ordinary work `node`, in the overlay's view: the one that work held, if any. Work + * at or below a background task holds nothing above it. + */ + #nearestLiveAbove(node, overlay) { + this.#record(INTENT_KEY); + for (let current = node; !current.background; ) { + const owner = current.owner ?? this.#edge(current.conversationId, overlay); + if (owner === void 0 || owner === null) + return void 0; + const record = overlay?.tasks.get(owner) ?? this.#liveRecord(owner); + if (record !== void 0 && record.state.status !== "terminal") + return record; + const above = record ?? this.#settled.get(owner); + if (above === void 0) + return void 0; + current = above; + } + return void 0; + } + /** Whether the chain above `node` is loaded, without walking: known tasks outside `#unloaded` have a loaded chain. */ + #known(node) { + if (typeof node !== "string") { + return (this.#live.has(node) || this.#settled.has(node)) && !this.#unloaded.has(node); + } + const owner = this.#edges.get(conversationOf(node)); + return owner === null || owner !== void 0 && this.#known(owner); + } + /** Owner task of a conversation, `null` when ownerless, `undefined` while not loaded. */ + #edge(id, overlay) { + if (overlay?.edges.has(id) === true) + return overlay.edges.get(id); + this.#record(conversationKey(id)); + return this.#edges.get(id); + } + #node(id, overlay) { + return overlay?.tasks.get(id) ?? this.#live.get(id) ?? this.#settled.get(id); + } + /** Walk up from `start`: owner tasks and conversations, ending at an ownerless root or an edge not loaded yet. */ + *#above(start, overlay) { + let at = start; + while (at !== void 0) { + if ("task" in at) { + const node = this.#node(at.task, overlay); + if (node === void 0) { + yield { unknown: true }; + return; + } + yield { task: at.task, node }; + at = parentOf(node); + } else { + yield { conversation: at.conversation }; + const edge = this.#edge(at.conversation, overlay); + if (edge === void 0) { + yield { unknown: true }; + return; + } + at = edge === null ? void 0 : { task: edge }; + } + } + } + /** + * The tasks below `start` that a walk down reaches: those `#below` lists and, under an overlay, the commit's new tasks, + * with its candidates in place of committed records. Background tasks are reached but not entered, unless + * `crossBackground`, and neither are the tasks `enter` rejects. A loop, as chains can be deeper than the call stack. + */ + *#walkDown(start, options = {}) { + const { overlay, crossBackground = false, enter } = options; + const links = overlay === void 0 ? void 0 : this.#links(overlay); + const pending = [start]; + for (let at = pending.pop(); at !== void 0; at = pending.pop()) { + this.#record(ownedKey(at)); + for (const children of [this.#below.get(at), links?.get(at)]) { + for (const child of children ?? []) { + if (typeof child === "string") { + pending.push(child); + continue; + } + const record = overlay?.tasks.get(child) ?? this.#live.get(child); + const node = record ?? this.#settled.get(child); + if (node === void 0) + continue; + const live = record !== void 0 && record.state.status !== "terminal" ? record : void 0; + yield { id: child, node, live }; + if ((crossBackground || !node.background) && (enter === void 0 || enter(child))) + pending.push(child); + } + } + } + } + /** + * The links walks down need for the commit's new tasks: each one under its parent node, then each node above it that + * `#below` does not list yet, until one it lists, a live task (always listed), or the chain's end. + */ + #links(overlay) { + if (overlay.links !== void 0) + return overlay.links; + const links = /* @__PURE__ */ new Map(); + for (const record of overlay.tasks.values()) { + if (this.#live.has(record.id) || this.#settled.has(record.id)) + continue; + let child = record.id; + let parent = parentNode(record); + while (parent !== void 0 && parent !== null && links.get(parent)?.has(child) !== true) { + addTo(links, parent, child); + if (typeof parent !== "string" && (this.#live.has(parent) || overlay.tasks.has(parent))) + break; + let above; + if (typeof parent === "string") { + above = this.#edge(conversationOf(parent), overlay); + } else { + const fields = this.#settled.get(parent); + above = fields === void 0 ? void 0 : parentNode(fields); + } + if (above !== void 0 && above !== null && this.#below.get(above)?.has(parent) === true) + break; + child = parent; + parent = above; + } + } + overlay.links = links; + return links; + } + /** + * The live ordinary owned work of `owner` (spec §5.5): the live non-background tasks below it that a walk down reaches + * without entering a background task; with `first`, only the first. Candidates in `overlay` replace committed records; + * the walk does not enter tasks in `done`, which have none. Owner chains must be loaded. + */ + #ownedLive(owner, options = {}) { + const { overlay, first = false, done } = options; + const found = []; + const walk = this.#walkDown(owner, { + ...overlay === void 0 ? {} : { overlay }, + ...done === void 0 ? {} : { enter: (id) => !done.has(id) } + }); + for (const { id, node, live } of walk) { + if (live === void 0 || node.background) + continue; + found.push(id); + if (first) + break; + } + return found; + } + #hasOwnedLive(owner, overlay, done) { + const options = { + first: true, + ...overlay === void 0 ? {} : { overlay }, + ...done === void 0 ? {} : { done } + }; + return this.#ownedLive(owner, options).length > 0; + } + /** + * Whether ordinary traversal from `scope` reaches `start`: walking up reaches the scope's conversation, or an + * ownerless one for `roots`, without crossing a background owner, unless `crossBackground`. `undefined` while an + * edge is not loaded. + */ + #inScope(start, scope, crossBackground = false) { + this.#record(INTENT_KEY); + for (const step of this.#above(start)) { + if ("unknown" in step) + return void 0; + if ("conversation" in step) { + if ("conversation" in scope && step.conversation === scope.conversation) + return true; + } else if (step.node.background && !crossBackground) { + return false; + } + } + return "roots" in scope; + } + /** + * Whether a live owner's cancellation intent reaches `start`: walking up finds an owner with intent before a + * background owner without it. Terminal owners never cascade (spec §5.4). + */ + #belowCancelled(start) { + return this.#cancellingOwner(start) !== void 0; + } + /** The nearest live owner above `start` whose cancellation intent reaches it, if any; see `#belowCancelled`. */ + #cancellingOwner(start) { + this.#record(INTENT_KEY); + if (this.#intent.size === 0) + return void 0; + for (const step of this.#above(start)) { + if ("unknown" in step) + return void 0; + if (!("task" in step)) + continue; + const live = this.#live.get(step.task); + if (live !== void 0 && cancellationIntent(live)) + return live; + if (step.node.background) + return void 0; + } + return void 0; + } + /** + * Count a task in or out of `pi.durable.tasks.active`. Commit observers count at a commit's publication, which must not + * throw, so a throwing adapter is reported. + */ + #countActive(delta, kind) { + try { + this.#activeMetric.add(delta, { task: kind }); + } catch (error) { + this.#report(error, TELEMETRY2); + } + } + /** Fail the Session, which reports it, for a throw in one of the scheduler's own commits; ignored once closing. */ + #failSession(error, context) { + if (!this.#closing) + this.#session.fail(error, context); + } + /** Close listener: runs synchronously once admission is sealed, before `join()`, or when the Session fails. */ + #seal() { + for (const record of this.#live.values()) + this.#countActive(-1, record.kind); + this.#resumed.clear(); + this.#closing = true; + try { + this.#unsubscribeRegistry(); + } catch (error2) { + this.#report(error2, REGISTRY); + } + const error = closedError(this.#session); + this.#taskWaiters.rejectAll(error); + this.#idleWaiters.rejectAll(error); + this.#contexts.clear(); + this.#idleOrder.clear(); + this.#expiry?.disarm(); + this.#expiry = void 0; + this.#timer?.disarm(); + this.#timer = void 0; + } + /** + * Recompute the wake in a microtask the line never waits for, with no order relative to host commit listeners (one + * already queued serves later changes too): arm the built-in timer, or tell `onWake` of a change. + */ + #scheduleWake() { + if (this.#wakeScheduled || this.#closing || this.#readOnly) + return; + this.#wakeScheduled = true; + queueMicrotask(() => { + this.#wakeScheduled = false; + if (this.#closing) + return; + const wake = this.wake(); + if (this.#onWake === void 0) { + this.#armTimer(this.#enabled ? wake.at : void 0); + return; + } + const last = this.#lastWake; + if (last !== void 0 && last.active === wake.active && last.at === wake.at) + return; + try { + this.#onWake(wake); + this.#lastWake = wake; + } catch (error) { + this.#report(error, ON_WAKE); + } + }); + } + /** + * Keep the timer for the earliest sleep. It keeps the process alive, unlike the context expiry timer: a process with a + * sleeping task has work left, such as a retry backoff. Rechecks the clock when it fires, so a wake before `until` + * only arms it again. + */ + #armTimer(at) { + if (this.#timer !== void 0 && this.#timer.at === at) + return; + this.#timer?.disarm(); + this.#timer = void 0; + if (at === void 0 || this.#closing) + return; + const disarm = this.#timers.foreground(() => { + this.#timer = void 0; + this.#wakeDue(); + this.#kick(); + }, at - this.#now()); + this.#timer = { at, disarm }; + } + /** Make every sleeping task whose time has come a reservation candidate. */ + #wakeDue() { + for (const id of this.#sleeping) { + const record = this.#live.get(id); + if (record !== void 0 && !this.#notDue(record)) + this.#runnable.add(id); + } + } + /** + * The report info of a task's failure, with the extension that installed its definition: the code that failed is + * that extension's. Built-in tasks have none. + */ + /** What a report about `task`'s own code says of it: the task, and the extension that installed its definition. */ + #aboutTask(task) { + let extension; + if ("extension" in task) + extension = task.extension; + else { + try { + const snapshot = this.#registry.snapshot(); + extension = installerOf(snapshot, snapshot.task(task.kind)); + } catch { + } + } + return { task: reportTask(task), ...optionalExtension(extension) }; + } + /** `settings.restartLimit`, or the default when the host's settings throw. */ + #restartLimit() { + try { + return this.#settings().restartLimit; + } catch (error) { + this.#report(error, SETTINGS); + return DEFAULT_RESTART_LIMIT; + } + } + #notifyBlocked() { + for (const listener of [...this.#blockedListeners]) { + try { + listener(); + } catch (error) { + this.#report(error, { kind: "listener_error" }); + } + } + } + /** A sleep whose `until` the clock has not reached; an abort mark ends a sleep. */ + #notDue(record) { + const state = record.state; + return state.status === "sleeping" && !record.abortRequested && state.until > this.#now(); + } + #kick() { + this.#scheduleWake(); + this.#dirty = true; + if (this.#draining || !this.#enabled || this.#closing) + return; + this.#draining = true; + queueMicrotask(() => void this.#drain()); + } + async #drain() { + try { + while (this.#dirty && this.#enabled && !this.#closing) { + this.#dirty = false; + for (const reservation of await this.#reserve()) + this.#start(reservation); + } + } catch (error) { + this.#failSession(error); + } finally { + this.#draining = false; + if (this.#dirty) + this.#kick(); + } + } + /** + * Reserve every eligible task in one commit; orphan abort-marked tasks no definition can take, unless abandoned after + * a restart. The first pass after open only abort-marks the abandoned tasks, so later passes see the marks. + */ + async #reserve() { + const reservations = []; + const faulted = []; + let abandoned = []; + try { + await this.#session.commitInternal(async (tx) => { + if (!this.#enabled || this.#closing) + return; + if (this.#abandoned.size > 0) { + const ids = [...this.#abandoned]; + const unmarked = await this.#region(() => ids.map((id) => this.#liveRecord(id)).filter((record) => record !== void 0 && !record.abortRequested)); + for (const record of unmarked) + tx.setTask(withAbortMark(record, "restart")); + abandoned = ids; + return; + } + await this.#loadScopes(false); + this.#wakeDue(); + const plan = await this.#region(() => this.#planReservation(), this.#reloadScopes); + for (const id of plan.dropped) + this.#runnable.delete(id); + if (plan.cascade) { + this.#cascadePending = true; + this.#scheduleReconcile(); + } + let snapshot; + for (const record of plan.ready) { + const id = record.id; + const mode = record.abortRequested ? "abort" : "run"; + const cutOff = record.restarts !== void 0 && record.restarts >= this.#restartLimit(); + if (cutOff && (mode === "abort" || !this.#limitsRestarts(record.kind))) { + const message = mode === "abort" ? `Abort handler of task ${id} (${record.kind}) was cut off ${record.restarts} times` : `Task ${id} (${record.kind}) was cut off ${record.restarts} times without progress`; + await this.#terminate(tx, record, { + status: "faulted", + error: { message, detail: { reason: "restart_limit" } } + }); + faulted.push({ record, message }); + continue; + } + snapshot ??= this.#registry.snapshot(); + const resolution = this.#resolve(record, snapshot); + if (resolution.kind === "blocked") { + if (mode === "abort" && record.abortReason === void 0) { + await this.#terminate(tx, record, { status: "orphaned", reason: resolution.reason }); + } + continue; + } + if (resolution.record !== record || record.state.status !== "running") { + tx.setTask(withState(resolution.record, { + status: "running", + checkpoint: resolution.record.state.checkpoint + })); + } + this.#runnable.delete(id); + const invocation = this.#createInvocation(record, mode, installerOf(snapshot, resolution.task)); + reservations.push({ invocation, task: resolution.task, snapshot }); + } + }, this.#context); + } catch (error) { + for (const { invocation } of reservations) { + this.#invocations.delete(invocation.taskId); + this.#runnable.add(invocation.taskId); + invocation.finish(); + } + throw error; + } + for (const { record, message } of faulted) { + this.#report(new Error(message), { + kind: "task_faulted", + ...this.#aboutTask(recordTask(record)), + reason: "restart_limit" + }); + } + for (const id of abandoned) + this.#abandoned.delete(id); + if (abandoned.length > 0) + this.#dirty = true; + return reservations; + } + /** + * A reservation pass's decision region: the candidates it drops (gone, holding, waiting, asleep, or with an + * invocation), whether one waits for a cascade, and the runnable records to resolve. Iterating the candidates is not + * keyed: a pass that misses a task a pending commit makes runnable only delays it, as does skipping one with an + * invocation without reading its record, or a waiter's check whether what it waits on is still live. + */ + #planReservation() { + const dropped = []; + const ready = []; + let cascade = false; + for (const id of this.#runnable) { + if (this.#invocations.has(id)) { + dropped.push(id); + continue; + } + const record = this.#liveRecord(id); + if (record === void 0 || record.state.status === "completing" || this.#waitingOn(record, true).length > 0 || this.#notDue(record)) { + dropped.push(id); + continue; + } + if (!record.abortRequested && !record.background && this.#belowCancelled(parentOf(record))) { + cascade = true; + continue; + } + ready.push(record); + } + return { dropped, cascade, ready }; + } + /** + * Live tasks a task waits for before its next invocation: its live ordinary owned work when abort-marked, since + * abort runs bottom-up, otherwise the live part of the `on` of a wait. + */ + #waitingOn(record, first = false) { + if (record.abortRequested) + return this.#ownedLive(record.id, { first }); + if (record.state.status !== "waiting") + return []; + if (!first) + return record.state.on.filter((id) => this.#live.has(id)); + const live = record.state.on.find((id) => this.#live.has(id)); + return live === void 0 ? [] : [live]; + } + /** Resolve the record's definition by kind, migrating an older stored version. */ + #resolve(record, snapshot) { + const fit = this.#fit(record, snapshot.task(record.kind)); + if ("reason" in fit) + return { kind: "blocked", reason: fit.reason }; + if (!fit.migrates) + return { kind: "ready", task: fit.task, record }; + const definition = erased(fit.task); + try { + if (definition.migrate === void 0) + throw missingMigration(record, definition); + const migrated = definition.migrate(record.input, record.state.checkpoint, record.version); + const state = { ...record.state, checkpoint: copyJson(migrated.checkpoint) }; + const migratedRecord = { ...record, version: definition.version, input: copyJson(migrated.input), state }; + return { kind: "ready", task: fit.task, record: migratedRecord }; + } catch (error) { + this.#failedMigrations.set(record.id, { task: fit.task, error }); + queueMicrotask(() => this.#notifyBlocked()); + this.#scheduleWake(); + const extension = installerOf(snapshot, fit.task); + this.#report(error, { kind: "migration_failed", ...this.#aboutTask({ ...recordTask(record), extension }) }); + return { kind: "blocked", reason: "migration_failed" }; + } + } + #fit(record, task) { + if (task === void 0) + return { reason: "missing_task" }; + const version = task.definition.version; + if (version === record.version) + return { task, migrates: false }; + if (version < record.version) + return { reason: "task_too_old" }; + const failed = this.#failedMigrations.get(record.id); + if (failed?.task === task) + return { reason: "migration_failed", error: failed.error }; + return { task, migrates: true }; + } + /** Sizes of the ownership indexes, for tests that bound the scheduler's memory. */ + get indexSizes() { + let below = 0; + for (const children of this.#below.values()) + below += children.size; + return { + live: this.#live.size, + settled: this.#settled.size, + edges: this.#edges.size, + below, + roots: this.#roots.size, + unloaded: this.#unloaded.size, + dropQueue: this.#dropQueue.size, + pins: this.#pins.size + }; + } + /** + * The kept contexts' idle state, for tests (a diagnostic, computed on demand): how many are kept and how many are + * idle, how many disagree with a full recompute (an idle period without `#idle()`, or `#idle()` without one; an + * expiry order that differs from the idle periods, or is not sorted), and how many idle checks covered every scope. + */ + get idleState() { + let mismatches = 0; + let idle = 0; + for (const [conversationId, kept] of this.#contexts) { + if (kept.idleSince !== void 0) + idle++; + if (kept.idleSince !== void 0 !== this.#idle(conversationId)) + mismatches++; + if (this.#idleOrder.get(conversationId) !== kept.idleSince) + mismatches++; + } + let previous = Number.NEGATIVE_INFINITY; + for (const [conversationId, idleSince] of this.#idleOrder) { + if (idleSince < previous || this.#contexts.get(conversationId)?.idleSince !== idleSince) + mismatches++; + previous = idleSince; + } + return { + contexts: this.#contexts.size, + idleContexts: idle, + idleMismatches: mismatches, + fullIdleChecks: this.#fullIdleChecks + }; + } + /** + * Scheduling state and every live task with its derived state, read on the Session line. Runs no task code: a + * pending migration shows as `ready` with `migrates`, and only a migration the scheduler already tried, or one that + * cannot exist, shows as failed. + */ + async inspect(snapshot) { + await this.#published(); + await this.#loadScopes(false); + const tasks = []; + for (const record of this.#live.values()) + tasks.push({ record, state: this.#inspectTask(record, snapshot) }); + const scheduling = this.#closing ? "closing" : this.#enabled ? "running" : "paused"; + return { scheduling, tasks }; + } + #inspectTask(record, snapshot) { + if (this.#invocations.has(record.id)) + return { kind: "running" }; + if (record.state.status === "completing") + return { kind: "completing" }; + const on = this.#waitingOn(record); + if (on.length > 0) + return { kind: "waiting", on }; + if (this.#notDue(record)) + return { kind: "sleeping", until: record.state.until }; + const fit = this.#fit(record, snapshot.task(record.kind)); + if ("reason" in fit) + return { kind: "blocked", ...fit }; + if (fit.migrates && fit.task.definition.migrate === void 0) { + return { kind: "blocked", reason: "migration_failed", error: missingMigration(record, erased(fit.task)) }; + } + return { kind: "pending", migrates: fit.migrates }; + } + #createInvocation(record, mode, extension) { + const controller = new AbortController(); + const { promise: done, resolve: finish } = Promise.withResolvers(); + const invocation = { + taskId: record.id, + kind: record.kind, + extension, + conversationId: record.conversationId, + mode, + controller, + links: record.startedAt === void 0 ? record.links : void 0, + context: withAbortSignal(controller.signal, this.#context), + record, + watches: /* @__PURE__ */ new Set(), + timers: /* @__PURE__ */ new Set(), + ended: false, + done, + finish: () => finish() + }; + this.#invocations.set(record.id, invocation); + return invocation; + } + #start(reservation) { + const invocation = reservation.invocation; + void (async () => { + try { + if (invocation.mode === "run") + await this.#run(reservation); + else + await this.#runAbort(reservation); + } catch (error) { + this.#report(error, { kind: "task_error", ...this.#aboutTask(invocation) }, invocation.context); + } finally { + this.#end(invocation); + invocation.record = void 0; + invocation.links = void 0; + invocation.fault = void 0; + invocation.finish(); + this.#kick(); + } + })(); + } + /** Run phase handlers, each preceded by a step that decides on the line whether the invocation continues. */ + async #run(reservation) { + const invocation = reservation.invocation; + const state = { task: reservation.task, snapshot: reservation.snapshot, reported: void 0 }; + const phase = { snapshot: () => state.snapshot, task: () => state.task, agent: void 0 }; + const runtime = this.#runtime(invocation, phase); + const progress = (tx, current2) => this.#progress(tx, current2, state, invocation.extension, invocation.context); + let current = await this.#step(invocation, (task) => this.#rules(task, void 0), progress); + while (current !== void 0 && !this.#closing) { + const task = current; + current = await this.#phase(invocation, task, async () => { + const checkpoint = task.state.checkpoint; + phase.agent = void 0; + let previous; + try { + await erased(state.task).phases[checkpoint.phase](task, runtime, invocation.context); + previous = { checkpoint }; + } catch (error) { + previous = { checkpoint, failure: { error } }; + } + return this.#step(invocation, (next) => this.#rules(next, previous), progress); + }); + } + } + /** A phase owns its decision commit, not the next handler, a durable wait, or recovery. */ + #phase(invocation, task, run2) { + const parent = task.trace === void 0 ? this.#telemetry : this.#telemetry.propagation?.extract(task.trace) ?? this.#telemetry; + const checkpoint = task.state.checkpoint; + const attempt = checkpoint.attempt; + const resumed = this.#resumed.delete(task.id); + return createTypedSpanStarter(parent, [DURABLE_TELEMETRY_SCHEMA])("pi.durable.phase", { + "task.id": task.id, + "task.name": task.kind, + phase: checkpoint.phase, + kind: invocation.mode, + resumed, + ...attempt === void 0 ? {} : { attempt } + }, async (span) => { + if (span.propagation !== void 0 && invocation.links !== void 0) { + for (const carrier of invocation.links) + span.addLink({ context: span.propagation.extract(carrier) }); + } + const previous = invocation.context; + invocation.context = withTelemetry(span, previous); + const started = performance.now(); + try { + return await run2(); + } finally { + invocation.context = previous; + const state = invocation.record.state; + const terminal = invocation.fault ?? (state.status === "terminal" || state.status === "completing" ? state.outcome : void 0); + const outcome = terminal !== void 0 ? terminal.status === "completed" ? "done" : terminal.status === "aborted" ? "aborted" : "faulted" : state.status === "waiting" || state.status === "sleeping" ? state.status : invocation.ended || this.#closing ? "aborted" : `next=${state.checkpoint.phase}`; + span.setAttributes({ outcome }); + if (terminal?.status === "faulted" || terminal?.status === "failed" || terminal?.status === "orphaned") { + const message = terminal.status === "orphaned" ? terminal.reason : terminal.error.message; + span.setStatus({ + status: "error", + error: { name: `task_${terminal.status}`, message: ownedSlice2(message, 0, 500) } + }); + } else if (outcome === "aborted") { + span.setStatus({ status: "ok" }); + } + this.#durationMetric.record(performance.now() - started, { task: task.kind, phase: checkpoint.phase, outcome }, span); + } + }); + } + /** + * Precedence rules for a run invocation, a decision region of its step. Rules 1 (terminal, `completing`, `waiting`, or + * `sleeping`) and 2 (closing) are applied by `#step`. Progress (rule 5) is decided by `#progress()` once the decision + * stands, as it takes a registry snapshot. + */ + #rules(current, previous) { + if (current.abortRequested) + return END; + if (!current.background && this.#belowCancelled(parentOf(current))) + return CASCADE; + if (previous === void 0) + return CONTINUE; + if (previous.failure !== void 0) + return { kind: "fault", error: previous.failure.error }; + if (jsonEqual(current.state.checkpoint, previous.checkpoint)) { + const message = `Task ${current.kind} phase ${previous.checkpoint.phase} returned without durable progress`; + return { kind: "fault", error: new Error(message) }; + } + return PROGRESS; + } + /** + * Rule 5, progress: refresh the snapshot; hand over to a replacement definition that can take the task, writing it + * back as `pending`, or keep running under the old one, reported once per resolved definition. Returns whether the + * invocation continues. + */ + #progress(tx, current, state, extension, context) { + state.snapshot = this.#registry.snapshot(); + const next = state.snapshot.task(current.kind); + if (next === state.task) + return true; + if (next !== void 0 && canReserve(next, current)) { + tx.setTask(withState(current, { status: "pending", checkpoint: current.state.checkpoint })); + return false; + } + if (state.reported === void 0 || state.reported.task !== next) { + state.reported = { task: next }; + this.#report(new Error(`Task ${current.id} keeps running under its old ${current.kind} definition`), { + kind: "task_outdated", + ...this.#aboutTask({ ...recordTask(current), extension }), + reason: outdatedReason(next, current) + }, context); + } + return true; + } + /** Run the abort handler once; rules 1, 2, and 4 apply, and returning without an outcome faults. */ + async #runAbort(reservation) { + const invocation = reservation.invocation; + const current = this.#live.get(invocation.taskId); + if (current === void 0 || this.#closing) + return; + await this.#phase(invocation, current, async () => { + let failure; + try { + const phase = { + snapshot: () => reservation.snapshot, + task: () => reservation.task, + agent: void 0 + }; + const runtime = this.#runtime(invocation, phase); + await erased(reservation.task).abort(current, runtime, invocation.context); + } catch (error) { + failure = { error }; + } + const message = `Abort handler of task ${invocation.taskId} returned without a terminal outcome`; + await this.#step(invocation, () => ({ kind: "fault", error: failure?.error ?? new Error(message) })); + }); + } + /** + * One decision on the Session line, before a phase: a decision region (`#region()`) that reads the task's record. A + * task that is no longer running (rule 1: terminal, `completing`, `waiting`, or `sleeping`) or a closing Harness (rule + * 2) ends the invocation without a write; otherwise `plan` decides, and a decision that stands is applied: the + * invocation continues, with `progress` for rule 5, or ends, with a fault written. Ending happens inside the callback, + * before a fault's Harness cleanup. A rejected step, such as admission after close, also ends the invocation. Its + * outcome goes to the invocation only, so it is a scheduler commit (`commitInternal()`). + */ + async #step(invocation, plan, progress) { + let fault; + try { + const continued = await this.#session.commitInternal(async (tx) => { + const decided = await this.#region(() => { + const found = this.#liveRecord(invocation.taskId); + if (found?.state.status !== "running" || this.#closing) + return { plan: END }; + const current2 = found; + return { current: current2, plan: plan(current2) }; + }); + const { current } = decided; + const step = decided.plan; + if (step.kind === "continue") + return current; + if (step.kind === "progress" && progress(tx, current)) + return current; + this.#end(invocation); + if (step.kind === "cascade") { + this.#cascadePending = true; + this.#scheduleReconcile(); + } + if (step.kind === "fault") { + fault = { error: step.error }; + const message = errorMessage(step.error); + invocation.fault = { status: "faulted", error: { message } }; + await this.#terminate(tx, current, invocation.fault); + } + return void 0; + }, withoutAbortSignal(invocation.context)); + if (fault !== void 0) + this.#report(fault.error, { kind: "task_faulted", ...this.#aboutTask(invocation), reason: "threw" }, invocation.context); + return continued; + } catch (error) { + this.#end(invocation); + this.#failSession(error, invocation.context); + return void 0; + } + } + /** + * Write an outcome the scheduler decided. While the task's ordinary owned work is live it holds as `completing` and + * its Harness cleanup waits for the final commit (spec §5.5, rule 4); otherwise it is terminal with its cleanup. + */ + async #terminate(tx, record, outcome) { + await this.#loadScopes(false); + if (await this.#region(() => this.#hasOwnedLive(record.id, overlayOf(tx)), this.#reloadScopes)) { + tx.setTask(withState(record, { status: "completing", outcome })); + return; + } + tx.setTask(withState(record, { status: "terminal", outcome })); + await this.#settleOutcome(tx, record, outcome); + } + /** + * Replace a running task's state with what it committed. A terminal state holds as `completing` while ordinary owned + * work is live, judged on the commit's candidates, so work the same commit creates below the task counts. A wait is + * validated first. + */ + async #commitState(tx, invocation, current, next) { + if (next.status === "waiting") + await this.#validateWait(tx, invocation, current, next.on, next.policy); + if (next.status === "sleeping") + validateSleep(invocation, current.id, next.until); + if (next.status === "terminal") { + const overlay = overlayOf(tx); + await this.#loadScopes(false); + for (const record of overlay.tasks.values()) + await this.#loadChain(parentOf(record), overlay); + if (await this.#region(() => this.#hasOwnedLive(current.id, overlayOf(tx)), this.#reloadScopes)) { + tx.setTask(withState(progressed(current), { status: "completing", outcome: next.outcome })); + return; + } + } + const same = jsonEqual(current.state, next); + tx.setTask(withState(same ? current : progressed(current), next)); + } + /** + * A wait names existing tasks, and `failFast` only tasks the waiter owns. It may not close a cycle in the wait-for + * graph, whose edges run from each task to what it waits on and to its live ordinary owned work (spec §5.5); waiting + * on itself or on an owner holding it are the shortest such cycles. An abort handler cannot wait. + * + * Invariant: the wait-for graph is acyclic. Only a wait adds an edge between existing tasks, as a new task has only + * incoming edges, so checking each wait maintains it. + */ + async #validateWait(tx, invocation, current, on, policy) { + if (invocation.mode === "abort") + throw new Error(`Abort handler of task ${current.id} cannot wait`); + await this.#loadScopes(false); + const ended = /* @__PURE__ */ new Map(); + for (; ; ) { + const checked = await this.#region(() => this.#checkWait(current, on, policy, overlayOf(tx), ended), this.#reloadScopes); + if (checked === void 0) + return; + if ("missing" in checked) { + for (const id of checked.missing) + ended.set(id, await this.#session.lineStorage.task(id, this.#context) ?? null); + continue; + } + throw checked.error; + } + } + /** + * `#validateWait()`'s decision region: why the wait is refused, `undefined` when it may be stored, or the tasks in + * `on` it needs from Storage first, when `ended` lacks them. + */ + #checkWait(current, on, policy, overlay, ended) { + const targets = []; + const missing = []; + for (const id of on) { + const member = overlay.tasks.get(id) ?? this.#liveRecord(id) ?? ended.get(id); + if (member === void 0) { + missing.push(id); + continue; + } + if (member === null) + return { error: new Error(`Task ${id} does not exist`) }; + if (policy === "failFast" && member.owner !== current.id) { + return { error: new Error(`Task ${current.id} can wait failFast only on tasks it owns; ${id} is not one`) }; + } + if (member.state.status !== "terminal" && member.owner !== current.id) + targets.push(id); + } + if (missing.length > 0) + return { missing }; + if (targets.length === 0) + return void 0; + const cycle = this.#waitCycle(current.id, targets, overlay); + if (cycle === void 0) + return void 0; + return { + error: new Error(`Task ${current.id} cannot wait on ${cycle[0]}: ${[current.id, ...cycle].join(" -> ")} is a wait cycle`) + }; + } + /** + * The path from a member of `on` back to `task` in the wait-for graph, if the wait would close a cycle (spec §5.1). + * An edge X -> Y means X cannot settle before Y: Y is in the `on` of waiting X that is not abort-marked, or Y is live + * ordinary owned work of X, which holds X as `completing`. Each task is visited once and each subtree walked once, + * so a check is bounded by the live work it reaches. Part of a decision region: it records every record it reads. + * Owned work is found by walks down, which need the chains of every live task loaded. + */ + #waitCycle(task, on, overlay) { + const from = /* @__PURE__ */ new Map(); + const walked = /* @__PURE__ */ new Set(); + const pending = []; + const reach = (id, via) => { + if (from.has(id)) + return; + from.set(id, via); + pending.push(id); + }; + const path = (end) => { + const steps = []; + for (let at = end; at !== void 0; at = from.get(at)) + steps.unshift(at); + return steps; + }; + for (const id of on) + reach(id, void 0); + for (let id = pending.pop(); id !== void 0; id = pending.pop()) { + if (id === task) + return path(id); + const record = overlay.tasks.get(id) ?? this.#liveRecord(id); + if (record === void 0 || record.state.status === "terminal") + continue; + if (record.state.status === "waiting" && !record.abortRequested) { + for (const member of record.state.on) + reach(member, id); + } + if (walked.has(id)) + continue; + walked.add(id); + const found = []; + const walk = this.#walkDown(id, { overlay, enter: (below) => !walked.has(below) }); + for (const { id: below, node, live } of walk) { + if (live === void 0 || node.background) + continue; + found.push(below); + reach(below, id); + } + for (const below of found) + walked.add(below); + } + return void 0; + } + /** End an invocation: its runtime operations reject from now on, its signal aborts, its watches stop, and its task is free. */ + #end(invocation) { + if (invocation.ended) + return; + invocation.ended = true; + if (this.#invocations.get(invocation.taskId) === invocation) { + this.#invocations.delete(invocation.taskId); + if (this.#live.has(invocation.taskId)) + this.#runnable.add(invocation.taskId); + } + for (const watch of invocation.watches) + void watch.stop(); + for (const disarm of invocation.timers) + disarm(); + invocation.timers.clear(); + invocation.controller.abort(endedError(invocation)); + } + /** No live non-background task in the scope; a task whose owner edges are not loaded yet counts as inside. */ + #idle(conversationId) { + const scope = conversationId === void 0 ? { roots: true } : { conversation: conversationId }; + if (conversationId === void 0) + this.#record(ROOTS_KEY); + for (const id of this.#unloaded) { + const record = this.#live.get(id); + if (record !== void 0 && !record.background && this.#inScope(parentOf(record), scope) !== false) + return false; + } + const starts = conversationId === void 0 ? this.#roots : [conversationId]; + for (const start of starts) { + for (const { node, live } of this.#walkDown(conversationNode(start))) { + if (live !== void 0 && !node.background) + return false; + } + } + return true; + } + // ─── Invocation runtime ────────────────────────────────────────────────── + #runtime(invocation, phase) { + const agent = () => { + if (invocation.ended) + return Promise.reject(endedError(invocation)); + if (phase.agent === void 0) { + phase.agent = this.#agent(invocation.conversationId, phase.snapshot(), invocation.context); + phase.agent.catch(() => { + }); + } + return phase.agent; + }; + const hooks = { + each: async (name, invoke) => { + for (const { extension, handlers } of agentHooks(await agent(), phase.task().definition.name)) { + const handler = handlers[name]; + if (typeof handler !== "function") + continue; + try { + await invoke(handler.bind(handlers)); + } catch (error) { + if (invocation.controller.signal.aborted) + throw error; + this.#report(error, { kind: "extension_error", extension, task: reportTask(invocation) }, invocation.context); + } + } + } + }; + const settings = this.#settings; + const models2 = this.#models; + return { + taskId: invocation.taskId, + conversationId: invocation.conversationId, + signal: invocation.controller.signal, + get models() { + return models2(); + }, + agent: (context) => invocation.ended ? Promise.reject(endedError(invocation)) : awaitWithContext(agent(), context), + get settings() { + return settings(); + }, + env: (context) => this.#read(invocation, () => this.#env(invocation.conversationId, context)), + hooks, + get registry() { + return phase.snapshot(); + }, + commit: async (change, context, options) => { + let checkpoint; + let interrupted2; + await this.#gated(invocation, async (tx, current) => { + const next = await change(tx, current); + if (next !== void 0) + await this.#commitState(tx, invocation, current, next); + if (next?.status === "running" && current.state.checkpoint.phase !== next.checkpoint.phase) { + checkpoint = next.checkpoint.phase; + } + if (next?.status === "terminal") { + const restarts = current.restarts ?? 0; + const reason = next.outcome.status === "failed" ? interruptionOf(next.outcome.error) : void 0; + if (reason !== void 0 && next.outcome.status === "failed") { + interrupted2 = { message: next.outcome.error.message, reason, restarts }; + } else { + const message = endedByCrashesStates.get(next); + if (message !== void 0) + interrupted2 = { message, reason: "restart_limit", restarts }; + } + } + }, context, options); + if (interrupted2 !== void 0) { + this.#report(new Error(interrupted2.message), { + kind: "task_interrupted", + ...this.#aboutTask(invocation), + reason: interrupted2.reason, + restarts: interrupted2.restarts + }, invocation.context); + } + if (checkpoint !== void 0) { + invocation.context.telemetry.addEvent("pi.durable.checkpoint", { + phase: checkpoint + }); + } + }, + memo: ((name, ...rest) => { + if (rest.length === 1) { + return this.#read(invocation, async () => memoOf(this.#live.get(invocation.taskId), name)); + } + const candidate = rest[0]; + return this.#gated(invocation, (tx, current) => { + const winner = memoOf(current, name); + if (winner !== void 0) + return winner; + tx.setTask({ ...current, memos: { ...current.memos, [name]: candidate } }); + return candidate; + }, rest[1]); + }), + sleepUntil: (until, checkpoint, context) => this.#gated(invocation, (tx, current) => this.#commitState(tx, invocation, current, { status: "sleeping", checkpoint, until }), context), + watchDoc: ((...args) => this.#watchDoc(invocation, args)), + snapshot: ((...args) => this.#read(invocation, () => sessionMethod(this.#session, "snapshot")(...args))), + snapshotAsOf: ((...args) => this.#read(invocation, () => sessionMethod(this.#session, "snapshotAsOf")(...args))), + getTask: ((id, context) => this.#read(invocation, () => this.#session.readOnLine((storage) => storage.task(id, context)))), + waitForTask: ((id, context) => this.#read(invocation, () => this.waitForTask(id, withAbortSignal(invocation.controller.signal, context)))), + ownedTasks: (context) => this.#read(invocation, () => this.#session.readOnLine(async () => { + if (invocation.ended) + throw endedError(invocation); + context.abortSignal?.throwIfAborted(); + const owned = await this.#region(() => { + this.#record(ownedKey(invocation.taskId)); + const records = []; + for (const node of this.#below.get(invocation.taskId) ?? []) { + const record = typeof node === "string" ? void 0 : this.#liveRecord(node); + if (record?.owner === invocation.taskId) + records.push(record); + } + return records; + }); + return owned.sort((a, b) => a.id - b.id).map((record) => copyJson(record)); + })), + abortOwned: (id, context) => this.#read(invocation, async () => { + const bound = withAbortSignal(invocation.controller.signal, context); + const record = await this.#session.readOnLine((storage) => storage.task(id, bound)); + if (record?.owner !== invocation.taskId) { + throw new Error(`Task ${id} is not owned by task ${invocation.taskId}`); + } + if (record.state.status === "terminal") + return; + await this.abort(id, bound, true); + await this.waitForTask(id, bound); + }), + outcomes: ((ids, context) => this.#read(invocation, () => this.#session.readOnLine(async (storage) => { + const outcomes = []; + for (const id of ids) { + const state = (await storage.task(id, context))?.state; + if (state?.status !== "terminal") + throw new Error(`Task ${id} is not terminal`); + outcomes.push(state.outcome); + } + return outcomes; + }))), + conversation: (id, context) => this.#read(invocation, () => this.#conversation(id, { + signal: invocation.controller.signal, + check: () => { + if (invocation.ended) + throw endedError(invocation); + } + }, context)), + entry: ((...args) => { + const [token, id, context] = args.length === 2 ? [void 0, args[0], args[1]] : [args[0], args[1], args[2]]; + return this.#read(invocation, async () => { + const kept = this.#contexts.get(invocation.conversationId); + const entry2 = (kept === void 0 ? void 0 : rangeEntry(kept.range, id)) ?? (await this.#session.readOnLine((storage) => storage.entry(invocation.conversationId, id, context)))?.entry; + return token === void 0 || entry2?.kind === token.kind ? entry2 : void 0; + }); + }), + entries: (query, limit, cursor, context) => this.#read(invocation, () => this.#session.readOnLine((storage) => storage.scanEntries(conversationEntries(invocation.conversationId, query), limit, cursor, context))), + context: (conversationId, context, options) => this.#read(invocation, async () => { + const read2 = await readContextFrom(this.#session, this.#storage, conversationId, context, options?.at, this.#contexts.get(conversationId)?.range); + const { view: view2 } = read2; + const range = read2.range?.current === true && this.#session.knownLatestEntryId(conversationId) !== read2.range.bounds.tail ? { ...read2.range, current: false } : read2.range; + const kept = this.#contexts.get(conversationId); + if (range !== void 0 && !this.#closing && !invocation.ended && (kept === void 0 || kept.range.bounds.tail <= range.bounds.tail)) { + if (!this.#idle(conversationId)) { + this.#contexts.set(conversationId, { range, idleSince: void 0 }); + this.#idleOrder.delete(conversationId); + } else if (this.#contextRetentionMs() > 0) { + const idleSince = kept?.idleSince ?? this.#now(); + const expiresAt = kept?.idleSince !== void 0 && kept.expiresAt !== void 0 ? kept.expiresAt : idleSince + this.#contextRetentionMs(); + this.#contexts.set(conversationId, { range, idleSince, expiresAt }); + if (kept?.idleSince === void 0) + this.#markIdle(conversationId, idleSince); + this.#scheduleExpiry(); + } + } + return view2; + }), + now: () => { + if (invocation.ended) + throw endedError(invocation); + return this.#now(); + }, + setTimer: (callback, delayMs) => { + if (invocation.ended) + return () => { + }; + const disarm = this.#timers.foreground(() => { + invocation.timers.delete(disarm); + if (!invocation.ended) + callback(); + }, delayMs); + invocation.timers.add(disarm); + return () => { + invocation.timers.delete(disarm); + disarm(); + }; + }, + report: (error, from) => { + if (invocation.ended) + throw endedError(invocation); + const task = reportTask(invocation); + this.#report(error, from === void 0 ? { kind: "task_error", ...this.#aboutTask(invocation) } : from.kind === "extension" ? { kind: "extension_error", task, ...optionalExtension(from.extension) } : { kind: "host_error", callback: from.callback, task }, invocation.context); + } + }; + } + /** + * On the line: wait until every commit admitted before is published, for a decision that reads what cannot be keyed, + * every live task (open, inspection) or every task a conversation abort reaches. + */ + async #published() { + const gate = this.#session.touch(ALL_KEYS); + if (gate !== void 0) + await gate; + } + /** Run a committed-state read unless the invocation has ended. */ + async #read(invocation, read2) { + if (invocation.ended) + throw endedError(invocation); + return read2(); + } + /** Commit after rereading the task on the line and gating the invocation. */ + #gated(invocation, change, context, options) { + if (invocation.ended) + return Promise.reject(endedError(invocation)); + return this.#session.commitWith(async (tx) => { + if (invocation.ended) + throw endedError(invocation); + if (this.#closing) + throw closedError(this.#session); + const current = await this.#region(() => { + const found = this.#liveRecord(invocation.taskId); + if (found === void 0) + throw new Error(`Task ${invocation.taskId} is terminal`); + if (found.state.status !== "running") + throw new Error(`Task ${invocation.taskId} is ${found.state.status}`); + if (invocation.mode === "run" && found.abortRequested) { + throw new Error(`Task ${invocation.taskId} has a durable abort mark`); + } + return found; + }); + if (invocation.ended) + throw endedError(invocation); + return change(tx, current); + }, context, { conversationId: invocation.conversationId, taskId: invocation.taskId }, options); + } + async #watchDoc(invocation, args) { + if (invocation.ended) + throw endedError(invocation); + const watch = await sessionMethod(this.#session, "watchDoc")(...args); + if (watch === void 0) + return void 0; + if (invocation.ended) { + void watch.stop(); + throw endedError(invocation); + } + invocation.watches.add(watch); + void watch.closed.then(() => invocation.watches.delete(watch)); + return watch; + } +}; +var REGISTRY = { kind: "host_error", callback: "registry" }; +var SETTINGS = { kind: "host_error", callback: "settings" }; +var ON_WAKE = { kind: "host_error", callback: "onWake" }; +var TELEMETRY2 = { kind: "host_error", callback: "telemetry" }; +function installerOf(snapshot, task) { + if (task === void 0) + return void 0; + return snapshot.installed().findLast((installed) => installed.tasks?.includes(task) === true)?.name; +} +function reportTask(task) { + return { id: task.taskId, kind: task.kind, conversationId: task.conversationId }; +} +function recordTask(record) { + return { taskId: record.id, kind: record.kind, conversationId: record.conversationId }; +} +var endedByCrashesStates = /* @__PURE__ */ new WeakMap(); +function endedByCrashes(state, message) { + endedByCrashesStates.set(state, message); + return state; +} +function interruptionOf(error) { + const detail = error.detail; + if (typeof detail !== "object" || detail === null || !("reason" in detail)) + return void 0; + return detail.reason === "restart_limit" || detail.reason === "interrupted" ? detail.reason : void 0; +} +function withAbortMark(record, reason) { + const { abortReason: _reason, restarts: _restarts, ...rest } = record; + return { ...rest, abortRequested: true, ...reason === void 0 ? {} : { abortReason: reason } }; +} +function cancellationIntent(record) { + return record.state.status !== "terminal" && (record.abortRequested || failedOutcome(record)); +} +function intentChanges(previous, next) { + return (previous?.abortRequested ?? false) !== next.abortRequested || previous?.abortReason !== next.abortReason || (previous !== void 0 && failedOutcome(previous)) !== failedOutcome(next) || (previous !== void 0 && cancellationIntent(previous)) !== cancellationIntent(next); +} +function failedOutcome(record) { + const state = record.state; + return (state.status === "completing" || state.status === "terminal") && state.outcome.status !== "completed"; +} +function parentOf(node) { + return node.owner !== void 0 ? { task: node.owner } : { conversation: node.conversationId }; +} +function nodeOf(record) { + return { + conversationId: record.conversationId, + ...record.owner === void 0 ? {} : { owner: record.owner }, + background: record.background + }; +} +function overlayOf(tx) { + const tasks = new Map(tx.stagedTasks().map((record) => [record.id, record])); + const edges = new Map(tx.stagedConversations().map((record) => [record.id, record.owner?.taskId ?? null])); + return { tasks, edges }; +} +function addTo(map, key, value2) { + const values = map.get(key); + if (values === void 0) + map.set(key, /* @__PURE__ */ new Set([value2])); + else + values.add(value2); +} +function deleteFrom(map, key, value2) { + const values = map.get(key); + if (values === void 0) + return; + values.delete(value2); + if (values.size === 0) + map.delete(key); +} +function memoOf(record, name) { + const memos = record?.memos; + return memos !== void 0 && Object.hasOwn(memos, name) ? memos[name] : void 0; +} +function sessionMethod(session, name) { + return session[name].bind(session); +} +function missingMigration(record, definition) { + return new Error(`Task ${record.kind} version ${definition.version} has no migration from ${record.version}`); +} +function erased(task) { + return task.definition; +} +function endedError(invocation) { + return new Error(`Task ${invocation.taskId} invocation has ended`); +} +function progressed(record) { + if (record.restarts === void 0) + return record; + const { restarts: _restarts, ...rest } = record; + return rest; +} +function withState(record, state) { + if (state.status !== "terminal" && state.status !== "completing") + return { ...record, state }; + const { memos: _memos, restarts: _restarts, ...rest } = record; + return { ...rest, state }; +} +function outdatedReason(task, record) { + if (task === void 0) + return "missing_task"; + return task.definition.version < record.version ? "task_too_old" : "migration_failed"; +} +function canReserve(task, record) { + const definition = task.definition; + return definition.version === record.version || definition.version > record.version && definition.migrate !== void 0; +} +function validateSleep(invocation, task, until) { + if (invocation.mode === "abort") + throw new Error(`Abort handler of task ${task} cannot sleep`); + if (typeof until !== "number" || !Number.isFinite(until) || until < 0) { + throw new Error(`Task ${task} cannot sleep until ${until}: not a time in milliseconds`); + } +} +function jsonEqual(left, right) { + if (left === right) + return true; + if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) + return false; + if (Array.isArray(left) || Array.isArray(right)) { + if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) + return false; + return left.every((value2, index) => jsonEqual(value2, right[index])); + } + const keys = Object.keys(left); + if (keys.length !== Object.keys(right).length) + return false; + return keys.every((key) => Object.hasOwn(right, key) && jsonEqual(left[key], right[key])); +} + +// node_modules/@earendil-works/chord/dist/output.js +var NEWLINE = 10; +var INVALID_OUTPUT = /[\x00-\x08\x0b-\x1f\ufff9-\ufffb]/g; +var ESCAPE_SEQUENCE = /\x1b[\]PX^_][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]|\x1b[\x20-\x2f]*[\x30-\x7e]/g; +var encoder = new TextEncoder(); +var decoder = new TextDecoder("utf-8", { ignoreBOM: true }); +function sanitizeOutput(text) { + return text.replace(ESCAPE_SEQUENCE, "").replace(INVALID_OUTPUT, ""); +} +function boundOutput(text, limits) { + const bytes = encoder.encode(text); + const [from, to] = limits.retain === "head" ? headRange(bytes, limits) : tailRange(bytes, limits); + const kept = bytes.subarray(from, to); + return { + text: kept.length === bytes.length ? text : decoder.decode(kept), + bytes: kept.length, + droppedBytes: bytes.length - kept.length, + droppedLines: lineCount(bytes) - lineCount(kept) + }; +} +function headRange(bytes, limits) { + if (limits.maxLines === 0 || limits.maxBytes === 0) + return [0, 0]; + let end = bytes.length; + let lines2 = 0; + for (let index = bytes.indexOf(NEWLINE); index !== -1; index = bytes.indexOf(NEWLINE, index + 1)) { + if (++lines2 === limits.maxLines) { + end = index + 1; + break; + } + } + if (end > limits.maxBytes) { + const newline = bytes.lastIndexOf(NEWLINE, limits.maxBytes - 1); + end = newline === -1 ? characterEnd(bytes, limits.maxBytes) : newline + 1; + } + return [0, end]; +} +function tailRange(bytes, limits) { + if (limits.maxLines === 0 || limits.maxBytes === 0) + return [bytes.length, bytes.length]; + const last = bytes[bytes.length - 1] === NEWLINE ? bytes.length - 2 : bytes.length - 1; + let start = 0; + let lines2 = 1; + for (let index = last < 0 ? -1 : bytes.lastIndexOf(NEWLINE, last); index !== -1; ) { + if (lines2 === limits.maxLines) { + start = index + 1; + break; + } + lines2++; + index = index === 0 ? -1 : bytes.lastIndexOf(NEWLINE, index - 1); + } + if (bytes.length - start > limits.maxBytes) { + const from = bytes.length - limits.maxBytes; + const newline = bytes.indexOf(NEWLINE, from - 1); + start = newline !== -1 && newline + 1 < bytes.length ? newline + 1 : characterStart(bytes, from); + } + return [start, bytes.length]; +} +function characterEnd(bytes, index) { + let end = index; + while (end > 0 && ((bytes[end] ?? 0) & 192) === 128) + end--; + return end; +} +function characterStart(bytes, index) { + let start = index; + while (start < bytes.length && ((bytes[start] ?? 0) & 192) === 128) + start++; + return start; +} +function lineCount(bytes) { + if (bytes.length === 0) + return 0; + let newlines = 0; + for (let index = bytes.indexOf(NEWLINE); index !== -1; index = bytes.indexOf(NEWLINE, index + 1)) + newlines++; + return newlines + (bytes[bytes.length - 1] === NEWLINE ? 0 : 1); +} +var OutputBuffer = class { + #limits; + /** + * Decoder of byte chunks. A string chunk or a skip ends an incomplete character of earlier bytes (it becomes U+FFFD); + * the next byte chunk then starts a new character. As in `StreamDecoder`, only a byte-order mark at the very start of + * the output is dropped, never a U+FEFF later in it. + */ + #decoder = new TextDecoder("utf-8", { ignoreBOM: true }); + #started = false; + /** Stored chunks: for head the start of the stream, for tail a suffix that still contains the next window. */ + #chunks = []; + #storedBytes = 0; + #storedNewlines = 0; + #full = false; + #totalBytes = 0; + #totalNewlines = 0; + #endsWithNewline = true; + constructor(limits) { + this.#limits = limits; + } + /** Bytes currently held; bounded by the limits plus one chunk. */ + get storedBytes() { + return this.#storedBytes; + } + /** + * Accept a chunk; returns whether anything was accepted. `skipped` is output omitted right before the chunk, which + * must be more than the tail window by at least one byte or line; only tail retention accepts it. + */ + push(chunk, skipped) { + const pending = typeof chunk === "string" || skipped !== void 0 ? this.#decoder.decode() : ""; + let text = typeof chunk === "string" ? chunk : this.#decoder.decode(chunk, { stream: true }); + const first = !this.#started && pending === "" && skipped === void 0; + if (pending !== "" || text !== "" || skipped !== void 0) + this.#started = true; + if (first && typeof chunk !== "string" && text.startsWith("\uFEFF")) + text = text.slice(1); + if (skipped === void 0) + return this.#accept(pending + text); + if (this.#limits.retain !== "tail") + throw new Error("Skipped output requires tail retention"); + this.#accept(pending); + this.#skip(skipped); + this.#accept(text); + return true; + } + /** Count omitted output; nothing stored before it can be in the window once the text after it arrives. */ + #skip(skipped) { + if (skipped.bytes === 0) + return; + this.#totalBytes += skipped.bytes; + this.#totalNewlines += skipped.newlines; + this.#endsWithNewline = skipped.endsWithNewline; + this.#chunks = []; + this.#storedBytes = 0; + this.#storedNewlines = 0; + } + /** Flush an incomplete trailing character as a replacement character; call when the stream ends. */ + end() { + this.#accept(this.#decoder.decode()); + } + #accept(text) { + if (text.length === 0) + return false; + const bytes = utf8ByteLength(text); + const newlines = countNewlines(text); + this.#totalBytes += bytes; + this.#totalNewlines += newlines; + this.#endsWithNewline = text.endsWith("\n"); + if (this.#full) + return true; + this.#chunks.push({ text, bytes, newlines }); + this.#storedBytes += bytes; + this.#storedNewlines += newlines; + if (this.#limits.retain === "head") { + this.#full = this.#storedBytes > this.#limits.maxBytes || this.#storedNewlines >= this.#limits.maxLines; + return true; + } + while (this.#chunks.length > 1) { + const first = this.#chunks[0]; + const bytesAfter = this.#storedBytes - first.bytes; + const newlinesAfter = this.#storedNewlines - first.newlines; + if (bytesAfter <= this.#limits.maxBytes + 1 && newlinesAfter <= this.#limits.maxLines + 1) + break; + this.#chunks.shift(); + this.#storedBytes = bytesAfter; + this.#storedNewlines = newlinesAfter; + } + return true; + } + /** Retained, sanitized output and what the limits dropped from the whole stream. */ + snapshot() { + const stored = this.#chunks.length === 1 ? this.#chunks[0].text : this.#chunks.map((chunk) => chunk.text).join(""); + const kept = boundOutput(stored, this.#limits); + const storedLines = lines(this.#storedNewlines, stored === "" || stored.endsWith("\n")); + const keptLines = storedLines - kept.droppedLines; + if (this.#limits.retain === "tail" || this.#chunks.length > 1) { + const text = this.#limits.retain === "tail" ? tailMargin(stored, this.#limits) : stored; + const bytes = this.#limits.retain === "tail" ? utf8ByteLength(text) : this.#storedBytes; + this.#chunks = text === "" ? [] : [{ text, bytes, newlines: countNewlines(text) }]; + this.#storedBytes = bytes; + this.#storedNewlines = this.#chunks[0]?.newlines ?? 0; + } + return { + text: sanitizeOutput(kept.text), + droppedBytes: this.#totalBytes - kept.bytes, + droppedLines: lines(this.#totalNewlines, this.#endsWithNewline) - keptLines + }; + } +}; +function tailMargin(text, limits) { + const bytes = encoder.encode(text); + const byteStart = bytes.length > limits.maxBytes ? characterEnd(bytes, bytes.length - limits.maxBytes - 1) : 0; + let lineStart = 0; + let newlines = 0; + for (let index = bytes.lastIndexOf(NEWLINE); index !== -1; index = bytes.lastIndexOf(NEWLINE, index - 1)) { + if (++newlines > limits.maxLines) { + lineStart = index; + break; + } + if (index === 0) + break; + } + const start = Math.max(byteStart, lineStart); + return start === 0 ? text : decoder.decode(bytes.subarray(start)); +} +function lines(newlines, terminated) { + return newlines + (terminated ? 0 : 1); +} +var runtimeBuffer = globalThis.Buffer; +var nonAsciiPattern = /[^\x00-\x7f]/; +function utf8ByteLength(content) { + if (runtimeBuffer) + return runtimeBuffer.byteLength(content, "utf8"); + const firstNonAscii = content.search(nonAsciiPattern); + if (firstNonAscii === -1) + return content.length; + let bytes = firstNonAscii; + for (let i = firstNonAscii; i < content.length; i++) { + const code = content.charCodeAt(i); + if (code <= 127) + bytes += 1; + else if (code <= 2047) + bytes += 2; + else if (code >= 55296 && code <= 56319 && i + 1 < content.length) { + const next = content.charCodeAt(i + 1); + if (next >= 56320 && next <= 57343) { + bytes += 4; + i++; + } else + bytes += 3; + } else + bytes += 3; + } + return bytes; +} +function countNewlines(text) { + let count = 0; + for (let index = text.indexOf("\n"); index !== -1; index = text.indexOf("\n", index + 1)) + count++; + return count; +} +var PROGRESS_BYTES_PER_SECOND = 100 * 1024; +var SYSTEM_CLOCK = { + now: () => Date.now(), + setTimer: (callback, delayMs) => { + const timer = setTimeout(callback, delayMs); + return () => clearTimeout(timer); + } +}; +var Progress = class { + #write; + #onError; + #minIntervalMs; + #clock; + #waiters = []; + #timer; + #inFlight; + #nextAt = 0; + #dirty = false; + #stopped = false; + constructor(write, onError, minIntervalMs, clock = SYSTEM_CLOCK) { + this.#write = write; + this.#onError = onError; + this.#minIntervalMs = minIntervalMs; + this.#clock = clock; + } + /** Schedule a commit. */ + mark() { + this.#dirty = true; + this.#schedule(); + } + /** Schedule a commit; the promise settles with the commit that includes this change. */ + markAndWait() { + const waiter = Promise.withResolvers(); + this.#waiters.push(waiter); + this.mark(); + return waiter.promise; + } + /** Stop committing and wait for the commit in flight; returns the waiters the final commit must settle. */ + async stop() { + this.#stopped = true; + this.#timer?.(); + this.#timer = void 0; + await this.#inFlight; + return this.#waiters.splice(0); + } + #schedule() { + if (this.#stopped || this.#timer !== void 0 || this.#inFlight !== void 0) + return; + const wait = this.#nextAt - this.#clock.now(); + if (wait <= 0) + this.#flush(); + else + this.#timer = this.#clock.setTimer(() => { + this.#timer = void 0; + this.#schedule(); + }, wait); + } + #flush() { + if (this.#stopped || !this.#dirty) + return; + this.#dirty = false; + const waiters = this.#waiters.splice(0); + const started = this.#clock.now(); + this.#inFlight = this.#write().then((bytes) => { + this.#nextAt = started + Math.max(this.#minIntervalMs, bytes * 1e3 / PROGRESS_BYTES_PER_SECOND); + for (const waiter of waiters) + waiter.resolve(); + }, (error) => { + this.#nextAt = started + this.#minIntervalMs; + for (const waiter of waiters) + waiter.reject(error); + this.#onError(error); + }).finally(() => { + this.#inFlight = void 0; + if (this.#dirty) + this.#schedule(); + }); + } +}; + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/date.js +var DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; +var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/; +function IsLeapYear(year) { + return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); +} +function IsDate(value2) { + const matches = DATE.exec(value2); + if (!matches) + return false; + const year = +matches[1]; + const month = +matches[2]; + const day = +matches[3]; + return month >= 1 && month <= 12 && day >= 1 && day <= (month === 2 && IsLeapYear(year) ? 29 : DAYS[month]); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/time.js +var TIME = /^(\d\d):(\d\d):(\d\d)(?:\.\d+)?(?:([Zz])|([+-])(\d\d):(\d\d))?$/; +function IsTime(value2, strictTimeZone = true) { + const matches = TIME.exec(value2); + if (!matches) + return false; + if (strictTimeZone && !matches[4] && !matches[5]) + return false; + const hr = +matches[1]; + const min = +matches[2]; + const sec = +matches[3]; + if (hr > 23 || min > 59 || sec > 60) + return false; + if (matches[5]) { + const tzH2 = +matches[6]; + const tzM2 = +matches[7]; + if (tzH2 > 23 || tzM2 > 59) + return false; + } + if (sec < 60) + return true; + const tzSign = matches[5] === "-" ? -1 : 1; + const tzH = +(matches[6] || 0); + const tzM = +(matches[7] || 0); + const totalUtcMin = hr * 60 + min - tzSign * (tzH * 60 + tzM); + return (totalUtcMin % 1440 + 1440) % 1440 === 1439; +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/date_time.js +function IsDateTime(value2) { + const dateTime = value2.split(/T/i); + return dateTime.length === 2 && IsDate(dateTime[0]) && IsTime(dateTime[1]); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/duration.js +var Duration = /^P((\d+Y(\d+M(\d+D)?)?|\d+M(\d+D)?|\d+D)(T(\d+H(\d+M(\d+S)?)?|\d+M(\d+S)?|\d+S))?|T(\d+H(\d+M(\d+S)?)?|\d+M(\d+S)?|\d+S)|\d+W)$/; +function IsDuration(value2) { + return Duration.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/email.js +var Email = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[^"\\]|\\[\x20-\x7e])*")@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*|\[(?:IPv6:[a-f0-9:]+|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})\])$/i; +function IsEmail(value2) { + return Email.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/pattern/pattern.js +var RE_RULE_HYPHEN_PLACEMENT = /^(?!-).*(? regexp.source).join("|"), "u"); +var RE_PERMITTED_CATEGORY = new RegExp([ + RE_LETTER, + RE_EUROPEAN_SEPARATOR, + RE_COMMON_SEPARATOR, + RE_NUMBER_DECIMAL, + RE_MARK_NONSPACING, + RE_MARK_SPACING_COMBINING, + RE_CONTEXTO_EXCEPTIONS, + RE_PVALID_EXCEPTIONS +].map((regexp) => regexp.source).join("|"), "u"); + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/label/ascii.js +function IsAsciiLabel(value2) { + return RE_RULE_HYPHEN_PLACEMENT.test(value2) && RE_RULE_NOT_RESERVED_ACE.test(value2) && RE_ASCII_LDH.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/format/puny.js +var PUNYCODE_BASE = 36; +var PUNYCODE_TMIN = 1; +var PUNYCODE_TMAX = 26; +var PUNYCODE_SKEW = 38; +var PUNYCODE_DAMP = 700; +var PUNYCODE_INITIAL_BIAS = 72; +var PUNYCODE_INITIAL_N = 128; +function ThrowDontCare() { + throw null; +} +function IsAcePrefixed(value2) { + return value2.toLowerCase().startsWith("xn--"); +} +function Adapt(delta, numPoints, firstTime) { + delta = firstTime ? Math.floor(delta / PUNYCODE_DAMP) : delta >> 1; + delta += Math.floor(delta / numPoints); + let k = 0; + while (delta > (PUNYCODE_BASE - PUNYCODE_TMIN) * PUNYCODE_TMAX >> 1) { + delta = Math.floor(delta / (PUNYCODE_BASE - PUNYCODE_TMIN)); + k += PUNYCODE_BASE; + } + return k + Math.floor((PUNYCODE_BASE - PUNYCODE_TMIN + 1) * delta / (delta + PUNYCODE_SKEW)); +} +function Decode(value2) { + const output = []; + let n = PUNYCODE_INITIAL_N; + let i = 0; + let bias = PUNYCODE_INITIAL_BIAS; + const delimIdx = value2.lastIndexOf("-"); + if (delimIdx > 0) { + for (let j = 0; j < delimIdx; j++) { + const cp = value2.charCodeAt(j); + if (cp >= 128) + ThrowDontCare(); + output.push(cp); + } + } + let inIdx = delimIdx < 0 ? 0 : delimIdx + 1; + while (inIdx < value2.length) { + const oldi = i; + let w = 1; + let k = PUNYCODE_BASE; + while (true) { + if (inIdx >= value2.length) + ThrowDontCare(); + const ch = value2.charCodeAt(inIdx++); + let digit; + if (ch >= 97 && ch <= 122) + digit = ch - 97; + else if (ch >= 48 && ch <= 57) + digit = ch - 48 + 26; + else + ThrowDontCare(); + i += digit * w; + const t = k <= bias ? PUNYCODE_TMIN : k >= bias + PUNYCODE_TMAX ? PUNYCODE_TMAX : k - bias; + if (digit < t) + break; + w *= PUNYCODE_BASE - t; + k += PUNYCODE_BASE; + } + const outLen = output.length + 1; + bias = Adapt(i - oldi, outLen, oldi === 0); + n += Math.floor(i / outLen); + i %= outLen; + output.splice(i, 0, n); + i++; + } + return String.fromCodePoint(...output); +} +function DigitToChar(digit) { + return digit < 26 ? String.fromCharCode(digit + 97) : String.fromCharCode(digit - 26 + 48); +} +var RE_REPLACE_NON_ASCII = new RegExp(RE_NON_ASCII.source, "gu"); +function Encode(input) { + const basic = input.replace(RE_REPLACE_NON_ASCII, ""); + const basicLength = basic.length; + const result = basicLength > 0 ? [basic, "-"] : []; + const codePoints2 = Array.from(input, (char) => char.codePointAt(0)); + let n = PUNYCODE_INITIAL_N; + let delta = 0; + let bias = PUNYCODE_INITIAL_BIAS; + let handledCPCount = basicLength; + while (handledCPCount < codePoints2.length) { + let m = Infinity; + for (const cp of codePoints2) { + if (cp >= n && cp < m) + m = cp; + } + delta += (m - n) * (handledCPCount + 1); + n = m; + for (const cp of codePoints2) { + if (cp < n) + delta++; + if (cp === n) { + let q = delta; + for (let k = PUNYCODE_BASE; ; k += PUNYCODE_BASE) { + const t = k <= bias ? PUNYCODE_TMIN : k >= bias + PUNYCODE_TMAX ? PUNYCODE_TMAX : k - bias; + if (q < t) + break; + const digit = t + (q - t) % (PUNYCODE_BASE - t); + result.push(DigitToChar(digit)); + q = Math.floor((q - t) / (PUNYCODE_BASE - t)); + } + result.push(DigitToChar(q)); + bias = Adapt(delta, handledCPCount + 1, handledCPCount === basicLength); + delta = 0; + handledCPCount++; + } + } + delta++; + n++; + } + return result.join(""); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/format/bidi.js +var RE_RTL_ALLOWED = /^(?:R|AL|AN|EN|ES|CS|ET|ON|BN|NSM)$/; +var RE_LTR_ALLOWED = /^(?:L|EN|ES|CS|ET|ON|BN|NSM)$/; +var RE_RTL_CLASSES = /^(?:R|AL|AN)$/; +function HasBidiChars(value2) { + if (IsAcePrefixed(value2)) { + try { + return HasRightToLeftCharacters(Decode(value2.slice(4).toLowerCase())); + } catch { + return false; + } + } + return HasRightToLeftCharacters(value2); +} +function GetBidiClass(codePoint) { + const char = String.fromCodePoint(codePoint); + return RE_EUROPEAN_NUMBER.test(char) ? "EN" : RE_ARABIC_INDIC_DIGIT.test(char) ? "AN" : ( + // Pattern.RE_EUROPEAN_SEPARATOR.test(char) ? 'ES' : // (no-spec-coverage) + // Pattern.RE_COMMON_SEPARATOR.test(char) ? 'CS' : // (no-spec-coverage) + RE_MARK_NONSPACING.test(char) ? "NSM" : RE_SCRIPT_HEBREW.test(char) ? "R" : RE_SCRIPT_ARABIC_LETTER.test(char) ? "AL" : RE_LETTER.test(char) ? "L" : "ON" + ); +} +function HasRightToLeftCharacters(value2) { + for (const ch of value2) + if (RE_RTL_CLASSES.test(GetBidiClass(ch.codePointAt(0)))) + return true; + return false; +} +function SatisfiesBidiRule(value2) { + let isRtl = false; + let allowed = RE_LTR_ALLOWED; + let sawEN = false; + let sawAN = false; + let isFirst = true; + for (const ch of value2) { + const bidiClass = GetBidiClass(ch.codePointAt(0)); + if (isFirst) { + if (bidiClass !== "L" && bidiClass !== "R" && bidiClass !== "AL") + return false; + isRtl = bidiClass === "R" || bidiClass === "AL"; + allowed = isRtl ? RE_RTL_ALLOWED : RE_LTR_ALLOWED; + isFirst = false; + } + if (!allowed.test(bidiClass)) + return false; + if (bidiClass === "EN") + sawEN = true; + else if (bidiClass === "AN") + sawAN = true; + } + if (isRtl && sawEN && sawAN) + return false; + return true; +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/label/unicode.js +function ExceedsMaxALabelLength(value2) { + return RE_NON_ASCII.test(value2) && Encode(value2).length + 4 > 63; +} +function HasInvalidHyphens(chars) { + if (chars[0] === "-" || chars[chars.length - 1] === "-") + return true; + return chars.slice(2).join("").startsWith("--"); +} +function IsUnicodeLabel(value2) { + if (ExceedsMaxALabelLength(value2)) + return false; + if (HasRightToLeftCharacters(value2) && !SatisfiesBidiRule(value2)) + return false; + const chars = [...value2]; + const codePoints2 = chars.map((c) => c.codePointAt(0)); + const length = codePoints2.length; + if (HasInvalidHyphens(chars)) + return false; + if (RE_COMBINING_MARK.test(chars[0])) + return false; + let hasJapanese = false; + for (let i = 0; i < length; i++) { + const codePoint = codePoints2[i]; + const char = chars[i]; + if (RE_RFC5892_DISALLOWED.test(char)) + return false; + if (!RE_PERMITTED_CATEGORY.test(char)) + return false; + if (RE_SCRIPT_JAPANESE.test(char)) + hasJapanese = true; + const prev = codePoints2[i - 1], next = codePoints2[i + 1]; + switch (codePoint) { + case 183: + if (prev !== 108 || next !== 108) + return false; + break; + // MIDDLE DOT (Catalan) + case 885: + if (!next || !RE_SCRIPT_GREEK.test(chars[i + 1])) + return false; + break; + // Greek KERAIA + case 1523: + case 1524: + if (!prev || !RE_SCRIPT_HEBREW.test(chars[i - 1])) + return false; + break; + // Hebrew GERESH + case 8204: + if (!prev || prev < 128 && !RE_VIRAMA.test(chars[i - 1])) + return false; + break; + case 8205: + if (!prev || !RE_VIRAMA.test(chars[i - 1])) + return false; + break; + case 12539: + break; + } + } + if (value2.includes("\u30FB") && !hasJapanese) + return false; + return true; +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/label/puny.js +function IsPunyLabel(value2) { + if (!IsAcePrefixed(value2)) + return false; + try { + const body = value2.slice(4).toLowerCase(); + if (body.lastIndexOf("-") === 0) + return false; + const decoded = Decode(body); + if (!RE_NON_ASCII.test(decoded)) + return false; + return IsUnicodeLabel(decoded); + } catch { + return false; + } +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/hostname.js +function IsValidLabelLength(value2) { + return value2.length > 0 && value2.length <= 63; +} +function IsLabel(value2) { + return IsValidLabelLength(value2) && (IsPunyLabel(value2) || IsAsciiLabel(value2)); +} +function IsHostname(value2) { + if (value2.length === 0 || value2.length > 253) + return false; + if (value2.charCodeAt(value2.length - 1) === 46) + return false; + return value2.split(".").every((label) => IsLabel(label)); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idna/idn-hostname.js +function IsValidLabelLength2(value2) { + return value2.length > 0 && value2.length <= 63; +} +function IsLabel2(value2) { + return IsValidLabelLength2(value2) && (IsPunyLabel(value2) || IsUnicodeLabel(value2)); +} +function NormalizeHostname(value2) { + return value2.replace(/[\uff01-\uff5e]/g, (char) => String.fromCharCode(char.charCodeAt(0) - 65248)).normalize("NFC").replace(/[\u00ad\u034f\u180b-\u180d\u200b\ufe00-\ufe0f\u{e0100}-\u{e01ef}]/gu, "").replace(/[\u002E\u3002\uFF0E\uFF61]/g, "."); +} +function IsIdnHostname(value2) { + if (value2.length === 0 || value2.includes(" ")) + return false; + const normalized = NormalizeHostname(value2); + if (normalized.length > 253) + return false; + const labels = normalized.split("."); + const hasBidiChars = labels.some((label) => HasBidiChars(label)); + return labels.every((label) => IsLabel2(label) && (!hasBidiChars || SatisfiesBidiRule(label))); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/hostname.js +function IsHostname2(value2) { + return IsHostname(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/idn_email.js +var IdnEmail = /^(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~\u{0080}-\u{10FFFF}-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~\u{0080}-\u{10FFFF}-]+)*|"(?:[^"\\]|\\.)*")@[\p{L}\p{N}](?:[\p{L}\p{N}-]{0,62})(?^`{|}\\]/; +var InvalidPercentEncoding = /%(?![0-9a-fA-F]{2})/; +function NarrowIpvFuture(value2) { + return value2.length < IpvFutureMatchMaxLength ? value2.replace(IpvFutureMatch, "[::1]") : value2; +} +function IsIri(value2) { + if (InvalidIriChars.test(value2)) + return false; + if (InvalidPercentEncoding.test(value2)) + return false; + return URL.canParse(NarrowIpvFuture(value2)); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/iri_reference.js +var InvalidIriChars2 = /[\x00-\x20\x7F\\]|%(?![0-9a-fA-F]{2})/; +var MalformedScheme = /^[a-zA-Z][a-zA-Z0-9+\-.]*\/\//; +function IsIriReference(value2) { + return !InvalidIriChars2.test(value2) && !MalformedScheme.test(value2) && URL.canParse(value2, "http://example.com"); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer.js +var JsonPointer = /^(?:\/(?:[^~/]|~0|~1)*)*$/; +function IsJsonPointer(value2) { + return JsonPointer.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/json_pointer_uri_fragment.js +var JsonPointerUriFragment = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i; +function IsJsonPointerUriFragment(value2) { + return JsonPointerUriFragment.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/regex.js +function IsRegex(value2) { + try { + new RegExp(value2, "u"); + return true; + } catch { + return false; + } +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/relative_json_pointer.js +var RelativeJsonPointer = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/; +function IsRelativeJsonPointer(value2) { + return RelativeJsonPointer.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri.js +var Uri = /^[a-z][a-z0-9+\-.]*:(?:\/\/(?:(?:[-a-z0-9._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:[\da-f]{1,4}:){6}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|::(?:[\da-f]{1,4}:){5}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:[\da-f]{1,4})?::(?:[\da-f]{1,4}:){4}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,1}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){3}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,2}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){2}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,3}[\da-f]{1,4})?::[\da-f]{1,4}:(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,4}[\da-f]{1,4})?::(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,5}[\da-f]{1,4})?::[\da-f]{1,4}|(?:(?:[\da-f]{1,4}:){0,6}[\da-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)|(?:[-a-z0-9._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[-a-z0-9._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[-a-z0-9._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; +function IsUri(value2) { + return Uri.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_reference.js +var UriReference = /^(?:[a-z][a-z0-9+\-.]*:(?:\/\/(?:(?:[-a-z0-9._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:[\da-f]{1,4}:){6}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|::(?:[\da-f]{1,4}:){5}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:[\da-f]{1,4})?::(?:[\da-f]{1,4}:){4}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,1}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){3}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,2}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){2}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,3}[\da-f]{1,4})?::[\da-f]{1,4}:(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,4}[\da-f]{1,4})?::(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,5}[\da-f]{1,4})?::[\da-f]{1,4}|(?:(?:[\da-f]{1,4}:){0,6}[\da-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)|(?:[-a-z0-9._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:\/\/(?:(?:[-a-z0-9._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:[\da-f]{1,4}:){6}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|::(?:[\da-f]{1,4}:){5}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:[\da-f]{1,4})?::(?:[\da-f]{1,4}:){4}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,1}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){3}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,2}[\da-f]{1,4})?::(?:[\da-f]{1,4}:){2}(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,3}[\da-f]{1,4})?::[\da-f]{1,4}:(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,4}[\da-f]{1,4})?::(?:[\da-f]{1,4}:[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d))|(?:(?:[\da-f]{1,4}:){0,5}[\da-f]{1,4})?::[\da-f]{1,4}|(?:(?:[\da-f]{1,4}:){0,6}[\da-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)|(?:[-a-z0-9._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[-a-z0-9._~!$&'()*+,;=@]|%[0-9a-f]{2})+(?:\/(?:[-a-z0-9._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\?(?:[-a-z0-9._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[-a-z0-9._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; +function IsUriReference(value2) { + return UriReference.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/uri_template.js +var UriTemplate = /^(?:(?:[^\x00-\x20"<>%\\^`{|}\x7f]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?:\.(?:[a-z0-9_]|%[0-9a-f]{2})+)*(?::[1-9]\d{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?:\.(?:[a-z0-9_]|%[0-9a-f]{2})+)*(?::[1-9]\d{0,3}|\*)?)*\})*$/i; +function IsUriTemplate(value2) { + return UriTemplate.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/url.js +function IsUrl(value2) { + return URL.canParse(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/typebox/uuid.js +var Uuid = /^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i; +function IsUuid(value2) { + return Uuid.test(value2); +} + +// node_modules/@earendil-works/pi-schema/dist/formats/index.js +var formats = Object.freeze({ + date: IsDate, + "date-time": IsDateTime, + duration: IsDuration, + email: IsEmail, + hostname: IsHostname2, + "idn-email": IsIdnEmail, + "idn-hostname": IsIdnHostname2, + ipv4: IsIPv4, + ipv6: IsIPv6, + iri: IsIri, + "iri-reference": IsIriReference, + "json-pointer": IsJsonPointer, + "json-pointer-uri-fragment": IsJsonPointerUriFragment, + regex: IsRegex, + "relative-json-pointer": IsRelativeJsonPointer, + time: IsTime, + uri: IsUri, + "uri-reference": IsUriReference, + "uri-template": IsUriTemplate, + url: IsUrl, + uuid: IsUuid +}); + +// node_modules/@earendil-works/pi-ai/dist/utils/validation.js +var validatorCache = /* @__PURE__ */ new WeakMap(); +function getValidator(schema) { + const cached = validatorCache.get(schema); + if (cached) { + return cached; + } + const validator = compile(schema, { formats, coerce: true, unresolvedRefs: "reject" }); + validatorCache.set(schema, validator); + return validator; +} +function formatValidationPath(pointer2) { + if (pointer2 === "") + return "root"; + return pointer2.slice(1).split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")).join("."); +} +function validateToolArguments(tool, toolCall) { + if (toolCall.argumentsError) { + throw new Error(`Invalid arguments for tool "${toolCall.name}": ${toolCall.argumentsError}`); + } + const result = getValidator(tool.parameters).parse(structuredClone(toolCall.arguments)); + if (result.ok) { + return result.value; + } + const errors = result.errors.map((error) => ` - ${formatValidationPath(error.path)}: ${error.message}`).join("\n"); + const errorMessage2 = `Validation failed for tool "${toolCall.name}": +${errors} + +Received arguments: +${JSON.stringify(toolCall.arguments, null, 2)}`; + throw new Error(errorMessage2); +} + +// node_modules/@earendil-works/pi-durable/dist/truncate.js +var DEFAULT_MAX_LINES = 2e3; +var DEFAULT_MAX_BYTES = 50 * 1024; + +// node_modules/@earendil-works/pi-durable/dist/harness/usage.js +var UsageDoc = defineDoc({ + kind: "pi.usage", + version: 1, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({ models: {}, tools: {} }), + checkpointWhen: () => true +}); +async function recordUsage(tx, conversationId, bucket, key, usage) { + const totals = (await tx.doc(UsageDoc, conversationId))[bucket]; + const total = Object.hasOwn(totals, key) ? totals[key] : void 0; + if (total === void 0) + totals[key] = copyJson(usage, { omitUndefinedProperties: true }); + else + addUsage(total, usage); +} +function addUsage(total, usage) { + total.input += usage.input; + total.output += usage.output; + total.cacheRead += usage.cacheRead; + total.cacheWrite += usage.cacheWrite; + total.totalTokens += usage.totalTokens; + if (usage.cacheWrite1h !== void 0) + total.cacheWrite1h = (total.cacheWrite1h ?? 0) + usage.cacheWrite1h; + if (usage.reasoning !== void 0) + total.reasoning = (total.reasoning ?? 0) + usage.reasoning; + total.cost.input += usage.cost.input; + total.cost.output += usage.cost.output; + total.cost.cacheRead += usage.cost.cacheRead; + total.cost.cacheWrite += usage.cost.cacheWrite; + total.cost.total += usage.cost.total; +} +function addUsageState(sum, state) { + for (const bucket of ["models", "tools"]) { + for (const [key, usage] of Object.entries(state[bucket])) { + const total = Object.hasOwn(sum[bucket], key) ? sum[bucket][key] : void 0; + if (total !== void 0) + addUsage(total, usage); + else + Object.defineProperty(sum[bucket], key, { + value: structuredClone(usage), + enumerable: true, + writable: true + }); + } + } +} + +// node_modules/@earendil-works/pi-durable/dist/harness/tool.js +var MADE_NESTED_CALLS = "pi.tool.madeNestedCalls"; +var NestedCallDoc = defineDocFamily({ + kind: "pi.tool.nested-call", + version: 1, + scope: "task", + family: true, + initial: () => ({}), + // The document retires with its task. + checkpointWhen: () => false +}); +var ToolTask = defineTask({ + name: "pi.tool", + version: 3, + initial: () => ({ phase: "call" }), + // Version 1 had only model-issued calls, without `kind`; version 3 added `unoffered`, absent in version 2 inputs. + migrate: (input, checkpoint, fromVersion) => ({ + input: fromVersion === 1 ? { kind: "model", ...input } : input, + checkpoint + }), + phases: { + call: async (task, runtime, context) => { + const call = await readCall(runtime, task.input, context); + if (cutOffTooOften(task, runtime)) + return endCutOff(runtime, task, call, context); + const tool = isUnoffered(task.input) ? void 0 : await resolveTool(runtime, task.input, call.name, context); + if (tool === void 0) { + const error = harnessError("tool_unavailable", `Tool ${call.name} is not available`); + return reject(runtime, task.input, call, void 0, error, context); + } + const prepared = prepare(tool, call.arguments); + const checked = "error" in prepared ? prepared : validate(tool, call, prepared.args); + if ("error" in checked) + return reject(runtime, task.input, call, tool, invalid(checked.error), context); + let args = checked.args; + let block; + await runtime.hooks.each("beforeTool", async (hook2) => { + if (block !== void 0) + return; + try { + const decision = await hook2({ ...call, arguments: args }, runtime, context); + if (decision?.block !== void 0) + block = decision.block; + else if (decision?.arguments !== void 0) + args = decision.arguments; + } catch (error) { + if (runtime.signal.aborted) + throw error; + block = errorMessage(error); + } + }); + if (block !== void 0) { + const blocked = harnessError("blocked", `Tool call blocked: ${block}`); + return reject(runtime, task.input, call, tool, blocked, context); + } + const validated = validate(tool, call, args); + if ("error" in validated) + return reject(runtime, task.input, call, tool, invalid(validated.error), context); + const final = copyJson(validated.args, { omitUndefinedProperties: true }); + await runtime.commit(async (tx) => { + const slot = toolSlot(await tx.doc(LiveDoc, runtime.conversationId), runtime.taskId); + if (slot !== void 0) + slot.status = "running"; + if (slot !== void 0 && "parentTaskId" in slot) + slot.arguments = final; + return void 0; + }, context, PROGRESS_COMMIT); + await runtime.commit(() => { + const intent = { phase: "execute", arguments: final, replay: tool.replay ?? "unsafe" }; + return { status: "running", checkpoint: intent }; + }, context); + await run(runtime, task.input, call, tool, final, context); + }, + /** Recovery after intent: rerun only when the stored and the current policy both say `safe`. */ + execute: async (task, runtime, context) => { + const { arguments: args, replay } = task.state.checkpoint; + const call = await readCall(runtime, task.input, context); + if (cutOffTooOften(task, runtime)) + return endCutOff(runtime, task, call, context); + const tool = await resolveTool(runtime, task.input, call.name, context); + if (replay === "safe" && tool?.replay === "safe") { + await runtime.commit(async (tx) => { + const slot = toolSlot(await tx.doc(LiveDoc, runtime.conversationId), runtime.taskId); + if (slot !== void 0) { + clearProgress(slot); + slot.status = "running"; + if ("parentTaskId" in slot) + slot.arguments = args; + } + return void 0; + }, context); + return run(runtime, task.input, call, tool, args, context); + } + const message = `Tool ${call.name} was interrupted and may have partially run`; + const ending = { status: "failed", message }; + await settleFromSlot(runtime, task.input, call, { tool }, ending, "interrupted", message, context); + } + }, + abort: async (task, runtime, context) => { + const call = await readCall(runtime, task.input, context); + const [code, message] = isUnoffered(task.input) ? ["tool_unavailable", `Tool ${call.name} is not available`] : task.abortReason !== "restart" ? ["aborted", `Tool ${call.name} was aborted`] : task.state.checkpoint.phase === "execute" ? ["interrupted", `Tool ${call.name} was interrupted by a restart and may have partially run`] : ["abandoned", `Tool ${call.name} was not started: its caller ended with a restart`]; + const hooks = (task.restarts ?? 0) < runtime.settings.restartLimit - 1 ? { tool: await toolForLimits(runtime, task.input, call.name, context) } : void 0; + await settleFromSlot(runtime, task.input, call, hooks, { status: "aborted" }, code, message, context); + } +}); +async function endCutOff(runtime, task, call, context) { + const message = `Tool ${call.name} was interrupted ${cutOffCount(task)}; it is not run again`; + const ending = { status: "failed", message, reason: "restart_limit" }; + const hooks = salvageable(task, runtime) ? { tool: await toolForLimits(runtime, task.input, call.name, context) } : void 0; + await settleFromSlot(runtime, task.input, call, hooks, ending, "restart_limit", message, context); +} +async function reject(runtime, input, call, tool, result, context) { + const settled = await afterHarnessResult(runtime, input, call, tool, result, void 0, context); + await settle2(runtime, input, call, COMPLETED, settled, context); +} +async function settleFromSlot(runtime, input, call, hooks, ending, code, message, context) { + const live = await runtime.snapshot(LiveDoc, runtime.conversationId, context); + const { result, truncation } = fromSlot(live === void 0 ? void 0 : toolSlot(live, runtime.taskId), code, message); + const settled = hooks !== void 0 ? await afterHarnessResult(runtime, input, call, hooks.tool, result, truncation, context) : truncation === void 0 ? result : { ...result, diagnostics: [...result.diagnostics ?? [], truncation] }; + await settle2(runtime, input, call, ending, settled, context); +} +async function toolForLimits(runtime, input, name, context) { + if (isUnoffered(input)) + return void 0; + return resolveTool(runtime, input, name, context).catch(() => void 0); +} +function isUnoffered(input) { + return input.kind === "model" && input.unoffered === true; +} +async function resolveTool(runtime, input, name, context) { + const agent = await runtime.agent(context); + return (input.kind === "model" ? agent.tools : agent.callable).find((tool) => tool.name === name); +} +function outputLimits(tool) { + return { + maxBytes: tool?.outputLimits?.maxBytes ?? DEFAULT_MAX_BYTES, + maxLines: tool?.outputLimits?.maxLines ?? DEFAULT_MAX_LINES, + retain: tool?.outputLimits?.retain ?? "head" + }; +} +async function readCall(runtime, input, context) { + if (input.kind === "nested") { + context.telemetry.setAttributes({ + "tool.name": input.call.name, + "tool.call_id": input.call.id + }); + return { ...input.call, parent: { taskId: input.parent, callId: input.parentCallId } }; + } + const entry2 = await runtime.entry(AssistantEntry, input.assistant, context); + const message = entry2?.model?.[0]; + const call = message?.role === "assistant" ? message.content.find((content) => content.type === "toolCall" && content.id === input.callId) : void 0; + if (call === void 0) + throw new Error(`Entry ${input.assistant} has no tool call ${input.callId}`); + context.telemetry.setAttributes({ + "tool.name": call.name, + "tool.call_id": call.id + }); + return call; +} +function prepare(tool, args) { + if (tool.prepareArguments === void 0) + return { args }; + try { + return { args: tool.prepareArguments(args) }; + } catch (error) { + return { error: errorMessage(error) }; + } +} +function validate(tool, call, args) { + try { + return { args: validateToolArguments(tool, { ...call, arguments: args }) }; + } catch (error) { + return { error: errorMessage(error) }; + } +} +function invalid(message) { + return harnessError("invalid_arguments", message); +} +async function run(runtime, input, call, tool, args, context) { + const limits = outputLimits(tool); + const reported = { output: new OutputBuffer(limits), limits, diagnostics: [], details: void 0 }; + const streams = input.kind === "model" || input.progress !== false; + const progress = publishProgress(runtime, reported, streams, context); + const admissions = []; + const resumes = tool.replay === "safe"; + let sequence2 = 0; + let madeNestedMemo; + let ended = false; + const assertLive = () => { + if (ended) + throw new Error(`Tool call ${call.id} has settled`); + }; + let env; + const api = { + taskId: runtime.taskId, + conversationId: runtime.conversationId, + callId: call.id, + registry: runtime.registry, + agent: runtime.agent, + get models() { + return runtime.models; + }, + get env() { + return env; + }, + now: () => runtime.now(), + output: (chunk, skipped) => { + assertLive(); + if (reported.output.push(chunk, skipped)) + progress.mark(); + }, + outputWindow: limits.retain === "tail" ? { + maxBytes: limits.maxBytes, + maxLines: limits.maxLines, + minIntervalMs: runtime.settings.progress.outputIntervalMs, + bytesPerSecond: PROGRESS_BYTES_PER_SECOND + } : void 0, + retainedOutput: () => { + assertLive(); + const retained = reported.output.snapshot(); + return { text: retained.text, truncated: retained.droppedBytes > 0 }; + }, + diagnostic: (diagnostic) => { + assertLive(); + reported.diagnostics.push(copyJson(diagnostic, { omitUndefinedProperties: true })); + progress.mark(); + }, + details: async (value2, detailsContext) => { + assertLive(); + detailsContext.abortSignal?.throwIfAborted(); + reported.details = copyJson(value2, { omitUndefinedProperties: true }); + const committed = progress.markAndWait(); + committed.catch(() => { + }); + return awaitWithContext(committed, detailsContext); + }, + commit: async (change, commitContext, options) => { + let result2; + await runtime.commit(async (tx) => { + result2 = await change(tx); + return void 0; + }, commitContext, options); + return result2; + }, + memo: runtime.memo, + createTask: async (task, input2, options, taskContext) => { + const child = options.ownership.kind === "task" && !resumes ? { abandonOnRestart: true, ...options } : options; + let id; + await runtime.commit(async (tx) => { + id = await tx.createTask(task, input2, child); + return void 0; + }, taskContext); + return id; + }, + getTask: runtime.getTask, + waitForTask: runtime.waitForTask, + conversation: runtime.conversation, + snapshot: runtime.snapshot, + snapshotAsOf: runtime.snapshotAsOf, + watchDoc: runtime.watchDoc, + executeTool: async (name, toolArgs, callContext, options = {}) => { + assertLive(); + const key = options.key ?? String(++sequence2); + if (options.key !== void 0) + checkKey(options.key); + madeNestedMemo ??= runtime.memo(MADE_NESTED_CALLS, true, callContext).catch((error) => { + madeNestedMemo = void 0; + throw error; + }); + const admission = madeNestedMemo.then(() => startNestedCall(runtime, call.id, name, toolArgs, { key, progress: options.progress, abandonOnRestart: !resumes }, callContext)); + admissions.push(admission); + const id = await admission; + const settled = await runtime.waitForTask(id, callContext); + const stored = (await runtime.snapshot(NestedCallDoc, runtime.taskId, key, callContext))?.result; + return stored === void 0 ? fallbackResult(id, name, settled.state.outcome) : copyJson(stored); + } + }; + let result; + let ending = COMPLETED; + let durationMs; + try { + env = await runtime.env(context); + const startedAt = performance.now(); + try { + result = await tool.execute(args, api, context); + } finally { + durationMs = Math.round(performance.now() - startedAt); + } + } catch (error) { + if (runtime.signal.aborted) { + ended = true; + for (const waiter of await progress.stop()) + waiter.reject(error); + throw error; + } + result = { isError: true, diagnostics: [toolDiagnostic("tool_error", errorMessage(error))] }; + ending = { status: "failed", message: `Tool ${call.name} threw` }; + } + ended = true; + await Promise.allSettled(admissions); + reported.output.end(); + const pending = await progress.stop(); + try { + const settled = await finalResult(runtime, input, call, tool, result, reported, context); + await settle2(runtime, input, call, ending, settled, context, durationMs); + } catch (error) { + for (const waiter of pending) + waiter.reject(error); + throw error; + } + for (const waiter of pending) + waiter.resolve(); +} +function progressClock(runtime) { + let last = 0; + return { + now: () => { + try { + last = runtime.now(); + } catch { + } + return last; + }, + setTimer: (callback, delayMs) => runtime.setTimer(callback, delayMs) + }; +} +function publishProgress(runtime, reported, enabled, context) { + let written = { text: "", details: void 0, diagnostics: 0 }; + return new Progress(async () => { + if (!enabled) + return 0; + const snapshot = reported.output.snapshot(); + const current = { text: snapshot.text, details: reported.details, diagnostics: reported.diagnostics.length }; + const added = reported.diagnostics.slice(written.diagnostics, current.diagnostics); + const detailsChanged = current.details !== written.details; + let bytes = 0; + if (snapshot.text !== written.text) { + const shared = snapshot.text.startsWith(written.text) ? written.text.length : overlap(written.text, snapshot.text, 65536); + bytes += utf8ByteLength(snapshot.text.slice(shared)); + } + if (detailsChanged) + bytes += utf8ByteLength(JSON.stringify(current.details ?? null)); + if (added.length > 0) + bytes += utf8ByteLength(JSON.stringify(added)); + await runtime.commit(async (tx) => { + const slot = toolSlot(await tx.doc(LiveDoc, runtime.conversationId), runtime.taskId); + if (slot === void 0) + return void 0; + if ((slot.output ?? "") !== snapshot.text) + slot.output = snapshot.text; + if (snapshot.droppedBytes > 0) + slot.droppedBytes = snapshot.droppedBytes; + if (snapshot.droppedLines > 0) + slot.droppedLines = snapshot.droppedLines; + if (detailsChanged && current.details !== void 0) { + assignJson(slot, "details", current.details); + } + if (added.length > 0) { + if (slot.diagnostics === void 0) + slot.diagnostics = []; + for (const diagnostic of added) + slot.diagnostics.push(diagnostic); + } + return void 0; + }, context, PROGRESS_COMMIT); + written = current; + return bytes; + }, (error) => { + if (!runtime.signal.aborted) + runtime.report(error); + }, runtime.settings.progress.outputIntervalMs, progressClock(runtime)); +} +async function finalResult(runtime, input, call, tool, result, reported, context) { + const harness2 = []; + const retained = result.output === void 0 ? reported.output.snapshot() : void 0; + const output = retained === void 0 ? result.output : retained.text === "" ? [] : [{ type: "text", text: retained.text }]; + let final = { + ...result, + output, + details: result.details === void 0 ? reported.details : result.details, + diagnostics: [...reported.diagnostics, ...result.diagnostics ?? []] + }; + await runtime.hooks.each("afterTool", async (hook2) => { + final = await hook2(call, final, runtime, context) ?? final; + }); + if (retained !== void 0 && retained.droppedBytes > 0 && final.output === output) { + harness2.push(truncated(retained, reported.limits.retain)); + } + const bounded = boundContent(final.output ?? [], reported.limits); + if (bounded.droppedBytes > 0) + harness2.push(truncated(bounded, reported.limits.retain)); + const broken = structuredOutputError(tool, final); + if (broken !== void 0) { + const { structuredOutput: _dropped, ...rest } = final; + if (input.kind === "nested") { + final = { ...rest, isError: true }; + harness2.push(toolDiagnostic("invalid_structured_output", broken)); + } else { + final = rest; + const extension = await runtime.agent(context).then((agent) => toolExtension(agent, tool.name), () => void 0); + runtime.report(new Error(broken), { kind: "extension", ...optionalExtension(extension) }); + } + } + if (input.kind === "nested" && tool.structuredOutputSchema === void 0) { + final = { ...final, structuredOutput: outputValue(bounded.content) }; + } + if (input.kind === "nested" && tool.structuredOutputSchema !== void 0 && final.isError === true && final.structuredOutput === void 0 && ![...final.diagnostics ?? [], ...harness2].some((diagnostic) => diagnostic.severity === "error")) { + const text = bounded.content.flatMap((item) => item.type === "text" ? [item.text] : []).join("\n"); + if (text !== "") + harness2.push(toolDiagnostic("tool_error", text)); + } + return { ...final, output: bounded.content, diagnostics: [...final.diagnostics ?? [], ...harness2] }; +} +async function afterHarnessResult(runtime, input, call, tool, result, truncation, context) { + let final = result; + await runtime.hooks.each("afterTool", async (hook2) => { + final = await hook2(call, final, runtime, context) ?? final; + }); + const harness2 = []; + if (truncation !== void 0 && final.output === result.output) + harness2.push(truncation); + const limits = outputLimits(tool); + const bounded = boundContent(final.output ?? [], limits); + if (bounded.droppedBytes > 0) + harness2.push(truncated(bounded, limits.retain)); + const { structuredOutput: _dropped, ...rest } = final; + const value2 = input.kind === "nested" && final.isError !== true && tool?.structuredOutputSchema === void 0 ? { structuredOutput: outputValue(bounded.content) } : {}; + return { ...rest, ...value2, output: bounded.content, diagnostics: [...rest.diagnostics ?? [], ...harness2] }; +} +var structuredValidators = /* @__PURE__ */ new WeakMap(); +function structuredOutputError(tool, result) { + const schema = tool.structuredOutputSchema; + const value2 = result.structuredOutput; + if (schema === void 0) { + return value2 === void 0 ? void 0 : `Tool ${tool.name} returned structuredOutput but declares no structuredOutputSchema`; + } + if (value2 === void 0) { + return result.isError === true ? void 0 : `Tool ${tool.name} returned no structuredOutput`; + } + let validator = structuredValidators.get(schema); + if (validator === void 0) { + validator = compile(schema, { formats, unresolvedRefs: "reject" }); + structuredValidators.set(schema, validator); + } + if (validator.check(value2)) + return void 0; + const [first] = validator.errors(value2); + const path = first?.path.slice(1).split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")).join(".") || "root"; + return `Tool ${tool.name} returned structuredOutput that does not match its schema: ${path}: ${first?.message ?? "invalid"}`; +} +async function settle2(runtime, input, call, ending, result, context, durationMs) { + const nestedIds = (await runtime.ownedTasks(context)).filter((record) => record.kind === ToolTask.definition.name && record.input.kind === "nested").map((record) => record.id); + const madeNested = await runtime.memo(MADE_NESTED_CALLS, context) === true; + await Promise.all(nestedIds.map((id) => runtime.abortOwned(id, context))); + await runtime.commit(async (tx) => { + const conversationId = runtime.conversationId; + const live = await tx.doc(LiveDoc, conversationId); + const slot = toolSlot(live, runtime.taskId); + let settled; + if (input.kind === "nested") { + const nested = nestedResult(runtime.taskId, result, durationMs); + if (nested.usage !== void 0) + await recordUsage(tx, conversationId, "tools", call.name, nested.usage); + const state = await tx.doc(NestedCallDoc, input.parent, input.key, null); + if (state.taskId !== runtime.taskId) + throw new Error(`Nested call ${call.id} is not in its caller's index`); + state.result = nested; + if (slot !== void 0 && "parentTaskId" in slot) { + finishSlot(slot); + slot.summary = summaryOf(nested, result.output ?? []); + } + settled = { kind: "nested" }; + } else { + const timing = { timestamp: runtime.now(), durationMs }; + const entry2 = await appendToolResult(tx, conversationId, call, result, timing); + if (slot !== void 0 && !("parentTaskId" in slot)) { + finishSlot(slot); + slot.entry = entry2.id; + } + const control = result.control === void 0 || ending.status !== "completed" ? {} : { control: copyJson(result.control, { omitUndefinedProperties: true }) }; + settled = { kind: "model", entryId: entry2.id, ...control }; + } + if (madeNested) + removeNestedSlots(live, runtime.taskId); + if (ending.status === "aborted") + return { status: "terminal", outcome: { status: "aborted", result: settled } }; + if (ending.status === "failed") { + const error = { + message: ending.message, + ...ending.reason === void 0 ? {} : { detail: { reason: ending.reason } } + }; + return { status: "terminal", outcome: { status: "failed", error, result: settled } }; + } + return { status: "terminal", outcome: { status: "completed", result: settled } }; + }, context); +} +function nestedResult(taskId, result, durationMs) { + const nested = { + taskId, + structuredOutput: result.structuredOutput, + isError: result.isError ?? false, + details: result.details, + diagnostics: result.diagnostics ?? [], + usage: result.usage, + durationMs + }; + return copyJson(nested, { + omitUndefinedProperties: true + }); +} +async function startNestedCall(runtime, parentCallId, name, args, options, context) { + const key = options.key; + const call = { + type: "toolCall", + id: `${parentCallId}/${key}`, + name, + arguments: copyJson(args, { omitUndefinedProperties: true }) + }; + let id; + let replayed = false; + await runtime.commit(async (tx) => { + const state = await tx.doc(NestedCallDoc, runtime.taskId, key, null); + const existing = state.taskId; + if (existing !== void 0) { + const input2 = (await tx.task(existing))?.input; + const same = input2?.kind === "nested" && input2.call.name === name && jsonEqual2(input2.call.arguments, call.arguments); + if (!same) + throw new Error(`Nested call ${call.id} was already made with another tool or other arguments`); + id = existing; + replayed = state.result !== void 0; + return void 0; + } + const input = { + kind: "nested", + parent: runtime.taskId, + parentCallId, + key, + call, + ...options.progress === false ? { progress: false } : {} + }; + const created = await tx.createTask(ToolTask, input, { + ownership: { kind: "task", taskId: runtime.taskId }, + abandonOnRestart: options.abandonOnRestart + }); + state.taskId = created; + const live = await tx.doc(LiveDoc, runtime.conversationId); + live.nestedTools ??= []; + const slot = { + callId: call.id, + parentCallId, + parentTaskId: runtime.taskId, + name, + taskId: created, + arguments: call.arguments, + status: "pending" + }; + live.nestedTools.push(slot); + id = created; + return void 0; + }, context); + if (replayed) { + context.telemetry.addEvent("pi.durable.replay", { "tool.name": name }); + } + return id; +} +function outputValue(output) { + if (output.length === 0) + return ""; + if (output.length > 1) + return output; + const [only] = output; + return only.type === "text" ? only.text : only; +} +function fallbackResult(taskId, name, outcome) { + const message = outcome.status === "faulted" ? `Tool ${name} failed: ${outcome.error.message}` : outcome.status === "orphaned" ? `Tool ${name} could not resume: ${outcome.reason}` : `Tool ${name} ended without a result`; + const error = harnessError(outcome.status, message); + return { taskId, isError: true, diagnostics: error.diagnostics ?? [] }; +} +var COMPLETED = { status: "completed" }; +function fromSlot(slot, code, message) { + const droppedBytes = slot?.droppedBytes ?? 0; + const result = { + output: slot?.output === void 0 || slot.output === "" ? [] : [{ type: "text", text: slot.output }], + isError: true, + ...slot?.details === void 0 ? {} : { details: slot.details }, + diagnostics: [...slot?.diagnostics ?? [], toolDiagnostic(code, message)] + }; + if (droppedBytes === 0) + return { result }; + return { result, truncation: truncated({ droppedBytes, droppedLines: slot?.droppedLines ?? 0 }) }; +} +function harnessError(code, message) { + return { output: [], isError: true, diagnostics: [toolDiagnostic(code, message)] }; +} +function toolDiagnostic(code, message) { + return { severity: "error", code, message }; +} +function truncated(dropped, retain) { + const kept = retain === void 0 ? "" : ` to its ${retain === "head" ? "beginning" : "end"}`; + return { + severity: "warn", + code: "truncated", + message: `Output truncated${kept}: ${dropped.droppedLines} lines, ${dropped.droppedBytes} bytes dropped` + }; +} +var MAX_SUMMARY_ERROR_CHARS = 500; +function summaryOf(result, output) { + const error = result.isError ? ownedSlice2(errorTextOf(result, output), 0, MAX_SUMMARY_ERROR_CHARS) : ""; + return { + isError: result.isError, + ...result.durationMs === void 0 ? {} : { durationMs: result.durationMs }, + ...result.usage === void 0 ? {} : { usage: result.usage }, + ...error === "" ? {} : { error } + }; +} +function errorTextOf(result, output) { + const errors = result.diagnostics.filter((diagnostic) => diagnostic.severity === "error"); + if (errors.length > 0) + return errors.map((diagnostic) => diagnostic.message).join("\n"); + return output.flatMap((item) => item.type === "text" ? [item.text] : []).join("\n"); +} +async function appendToolResult(tx, conversationId, call, result, meta) { + const { timestamp, durationMs } = meta; + const diagnostics = [...result.diagnostics ?? []]; + const content = [...result.output ?? []]; + if (diagnostics.length > 0) + content.push({ type: "text", text: renderDiagnostics(diagnostics) }); + const message = { + role: "toolResult", + toolCallId: call.id, + toolName: call.name, + content, + ...result.details === void 0 ? {} : { details: result.details }, + ...result.usage === void 0 ? {} : { usage: result.usage }, + isError: result.isError ?? false, + ...durationMs === void 0 ? {} : { durationMs }, + timestamp + }; + if (result.usage !== void 0) + await recordUsage(tx, conversationId, "tools", call.name, result.usage); + return tx.appendEntry(ToolResultEntry, conversationId, { model: [message], data: { diagnostics } }); +} +function renderDiagnostics(diagnostics) { + return ` +${diagnostics.map((diagnostic) => `[${diagnostic.severity}] ${diagnostic.message}`).join("\n")} +`; +} +function boundContent(content, limits) { + const texts = content.filter((item) => item.type === "text"); + const bounded = boundOutput(texts.map((item) => item.text).join(""), limits); + if (bounded.droppedBytes === 0) + return { content, droppedBytes: 0, droppedLines: 0 }; + const keep = limits.retain === "head" ? texts[0] : texts.at(-1); + const result = []; + for (const item of content) { + if (item.type !== "text") + result.push(item); + else if (item === keep) + result.push({ ...item, text: bounded.text }); + } + return { content: result, droppedBytes: bounded.droppedBytes, droppedLines: bounded.droppedLines }; +} +function checkKey(key) { + if (key === "" || key.includes("/") || key === "__proto__" || /^[1-9][0-9]*$/.test(key)) { + throw new Error(`Nested call key ${JSON.stringify(key)} must be non-empty, without "/", not "__proto__", and not a positive integer`); + } +} +function jsonEqual2(a, b) { + if (a === b) + return true; + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) + return false; + if (Array.isArray(a) || Array.isArray(b)) { + return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((item, i) => jsonEqual2(item, b[i])); + } + const keys = Object.keys(a); + return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && jsonEqual2(a[key], b[key])); +} + +// node_modules/@earendil-works/pi-durable/dist/harness/generation.js +var DEFAULT_POLL_AFTER_MS = 5e3; +var GenerationTask = defineTask({ + name: "pi.generation", + version: 2, + initial: () => ({ phase: "prepare", attempt: 1 }), + // Version 2 leaves calls to tools not offered in a sequential round's `pending`, flagged `unoffered` in their slots. + // A version 1 Harness would start their tool tasks unflagged, resolving the name, so it leaves version 2 blocked + // instead. A version 1 checkpoint has no such calls and is kept as it is. + migrate: (input, checkpoint) => ({ + input, + checkpoint + }), + phases: { + /** + * Render the system prompt and tool loadout and append the positional `pi.system` entries they need, then move to + * `request`. The agent and settings resolved here are fixed for this request. Only the Harness writes model + * context to a busy conversation, so the context read here is still current at the commit; display-only entries + * may land meanwhile. + */ + prepare: async (task, runtime, context) => { + if (cutOffTooOften(task, runtime)) + return endCutOff2(runtime, task, context); + const { conversationId } = runtime; + const agent = await runtime.agent(context); + const settings = runtime.settings; + const { model: model2, thinkingLevel } = agent; + const resolved = model2 === void 0 ? void 0 : runtime.models.getModel(model2.provider, model2.modelId); + if (model2 === void 0 || resolved === void 0) + return failNoModel(runtime, model2, context); + const { attempt, compacted, overflow, threshold: blocked } = task.state.checkpoint; + if (compacted !== void 0 && overflow !== void 0) { + const [outcome] = await runtime.outcomes([compacted], context); + if (outcome?.status !== "completed" || outcome.result.entryId === void 0) { + return failModelError(runtime, overflow, context); + } + } + if (compacted !== void 0 && blocked === true) { + const [outcome] = await runtime.outcomes([compacted], context); + if (outcome !== void 0 && outcome.status !== "completed") { + return failModelError(runtime, compactionFailure(outcome), context); + } + } + const view2 = await runtime.context(conversationId, context); + const last = view2.messages.findLast((message) => message.role !== "system"); + if (last?.role !== "user" && last?.role !== "toolResult") + return failNothingToAnswer(runtime, context); + const shown = replaySections(view2.messages); + let env; + try { + env = await runtime.env(context); + } catch (error) { + if (context.abortSignal?.aborted) + throw error; + runtime.report(error, { kind: "host", callback: "env" }); + } + const input = { conversationId, agent, env, shown: Object.fromEntries(shown), read: runtime }; + const desired = await renderSections(agent.sections, input, shown, (error, section2) => runtime.report(error, { + kind: "extension", + ...optionalExtension(sectionExtension(agent, section2.key)) + }), context); + const entries2 = planSystemEntries(view2, desired, agent.tools, runtime.now()); + const threshold = compacted === void 0 ? thresholdCompaction(view2, entries2, resolved.contextWindow, compactionPolicy(settings, model2)) : void 0; + if (threshold === "blocking") { + await runtime.commit(async (tx) => { + const child = await createCompaction(tx, conversationId, { reason: "threshold" }, runtime.taskId); + const checkpoint = { phase: "prepare", attempt, compacted: child, threshold: true }; + return { status: "waiting", checkpoint, on: [child], policy: "allSettled" }; + }, context); + return; + } + await runtime.commit(async (tx) => { + let cutoff = await tx.latestEntryId(conversationId); + for (const entry2 of entries2) + cutoff = (await tx.appendEntry(SystemEntry, conversationId, entry2)).id; + if (threshold === "background" && (await tx.doc(LiveDoc, conversationId)).compactions === void 0) { + await createCompaction(tx, conversationId, { reason: "threshold" }); + } + const request2 = { + attempt, + ...compacted === void 0 ? {} : { compacted }, + model: model2, + thinkingLevel, + streamOptions: settings.stream, + cutoff + }; + return { status: "running", checkpoint: { phase: "request", ...request2 } }; + }, context); + }, + request: async (task, runtime, context) => { + if (cutOffTooOften(task, runtime)) + return endCutOff2(runtime, task, context); + if (task.restarts !== void 0) + return interrupted(runtime, task.state.checkpoint, context); + const { attempt, compacted, model: ref, thinkingLevel, streamOptions, cutoff } = task.state.checkpoint; + const conversationId = runtime.conversationId; + await runtime.commit(async (tx) => { + const live = await tx.doc(LiveDoc, conversationId); + await convertPartial(tx, live, conversationId); + live.generation = { attempt }; + return void 0; + }, context, PROGRESS_COMMIT); + const model2 = runtime.models.getModel(ref.provider, ref.modelId); + if (model2 === void 0) + return failNoModel(runtime, ref, context); + const view2 = await runtime.context(conversationId, context, { at: cutoff }); + let messages = view2.messages; + await runtime.hooks.each("beforeRequest", async (hook2) => { + const replaced = await hook2({ messages }, runtime, context); + if (replaced !== void 0) + messages = replaced.messages; + }); + const options = { + ...streamOptions, + signal: runtime.signal, + telemetry: context.telemetry, + sessionId: await ensureProviderSessionId(runtime, context), + ...thinkingLevel === "off" ? {} : { reasoning: thinkingLevel }, + onPayload: (payload) => providerPayload(runtime, model2, payload, context) + }; + const message = await streamResponse(runtime, model2, messages, options, attempt, context); + const request2 = { attempt, compacted, model: ref, thinkingLevel, cutoff, messages: view2.messages }; + await classify(runtime, request2, message, context); + }, + /** After the backoff's sleep; a run before `until` (an early wake, or a record of an earlier version) sleeps again. */ + retry: async (task, runtime, context) => { + const { attempt, compacted, until, poll } = task.state.checkpoint; + if (cutOffTooOften(task, runtime)) + return endCutOff2(runtime, task, context); + if (until > runtime.now()) + return runtime.sleepUntil(until, task.state.checkpoint, context); + await runtime.commit(async (tx) => { + const live = await tx.doc(LiveDoc, runtime.conversationId); + const kept = compacted === void 0 ? {} : { compacted }; + if (poll !== void 0) { + const pollAt = runtime.now(); + live.generation = { attempt: attempt + 1, deferred: { pollAt } }; + return { + status: "running", + checkpoint: { phase: "poll", attempt: attempt + 1, ...kept, ...poll, pollAt } + }; + } + live.generation = { attempt: attempt + 1 }; + return { status: "running", checkpoint: { phase: "prepare", attempt: attempt + 1, ...kept } }; + }, context); + }, + /** After the sleep until `pollAt`; a run before it (an early wake, or a record of an earlier version) sleeps again. */ + poll: async (task, runtime, context) => { + const { attempt, compacted, model: ref, thinkingLevel, cutoff, handle, pollAt } = task.state.checkpoint; + if (cutOffTooOften(task, runtime)) + return endCutOff2(runtime, task, context); + if (task.restarts !== void 0) + return interrupted(runtime, task.state.checkpoint, context); + if (pollAt > runtime.now()) + return runtime.sleepUntil(pollAt, task.state.checkpoint, context); + const model2 = runtime.models.getModel(ref.provider, ref.modelId); + if (model2 === void 0) + return failNoModel(runtime, ref, context); + const message = await runtime.models.fetchDeferred(model2, handle, { + signal: runtime.signal, + telemetry: context.telemetry + }); + const request2 = { attempt, compacted, model: ref, thinkingLevel, cutoff, pollAt }; + await classify(runtime, request2, message, context); + }, + tools: async (task, runtime, context) => { + if (cutOffTooOften(task, runtime)) + return endCutOff2(runtime, task, context); + const { assistant, tools, pending } = task.state.checkpoint; + const [next, ...rest] = pending; + if (next === void 0) + return finishToolRound(runtime, assistant, tools, context); + await runtime.commit(async (tx) => { + const live = await tx.doc(LiveDoc, runtime.conversationId); + const slot = live.tools?.find((slot2) => slot2.callId === next && slot2.taskId === void 0); + const taskId = await createToolTask(tx, runtime, assistant, next, slot?.unoffered); + if (slot !== void 0) + slot.taskId = taskId; + const checkpoint = { + phase: "tools", + assistant, + tools: [...tools, taskId], + pending: rest + }; + return { status: "waiting", checkpoint, on: [taskId], policy: "allSettled" }; + }, context); + }, + /** + * Ask the `afterRun` hooks for tasks and create them, as the generation's children, in the commit that moves to + * `drain`; without any, end the run now. + */ + finish: async (task, runtime, context) => { + const { run: run2 } = task.state.checkpoint; + if (cutOffTooOften(task, runtime)) + return endAnsweredCutOff(runtime, task, run2.answer, context); + const prepared = []; + await runtime.hooks.each("afterRun", async (hook2) => { + const asked = await hook2(run2, runtime, context); + if (asked !== void 0) + prepareRunEndTasks(runtime, asked.tasks, prepared); + }); + if (prepared.length === 0) + return endAnsweredRun(runtime, run2.answer, context); + await runtime.commit(async (tx) => { + const tasks = []; + for (const { task: task2, input } of prepared) { + tasks.push(await tx.createTask(task2, input, { ownership: { kind: "task", taskId: runtime.taskId } })); + } + const live = await tx.doc(LiveDoc, runtime.conversationId); + if (live.run?.taskId === runtime.taskId && live.run.afterRun !== void 0) + live.run.afterRun.tasks = tasks; + const checkpoint = { phase: "drain", answer: run2.answer, tasks }; + return { status: "waiting", checkpoint, on: tasks, policy: "allSettled" }; + }, context); + }, + /** The after-run tasks are terminal, whatever their outcomes: end the run. */ + drain: async (task, runtime, context) => { + const { answer: answer2 } = task.state.checkpoint; + if (cutOffTooOften(task, runtime)) + return endAnsweredCutOff(runtime, task, answer2, context); + return endAnsweredRun(runtime, answer2, context); + } + }, + abort: async (task, runtime, context) => { + const checkpoint = task.state.checkpoint; + const polled = deferredOf(checkpoint); + if (polled !== void 0) + await cancelDeferred(runtime, polled, context); + const conversationId = runtime.conversationId; + const unstarted = checkpoint.phase === "tools" ? await readCalls(runtime, checkpoint.assistant, checkpoint.pending, context) : []; + await runtime.commit(async (tx) => { + const live = await tx.doc(LiveDoc, conversationId); + await convertPartial(tx, live, conversationId); + for (const call of unstarted) { + const unoffered = live.tools?.find((slot) => slot.callId === call.id)?.unoffered === true; + const result = unoffered ? harnessError("tool_unavailable", `Tool ${call.name} is not available`) : harnessError("aborted", `Tool ${call.name} was aborted`); + await appendToolResult(tx, conversationId, call, result, { timestamp: runtime.now() }); + } + endRun(tx, live, runtime.taskId, { status: "unanswered", reason: "aborted" }); + return { status: "terminal", outcome: { status: "aborted" } }; + }, context); + } +}); +async function readCalls(runtime, assistant, callIds, context) { + const message = (await runtime.entry(AssistantEntry, assistant, context))?.model?.[0]; + const calls = message?.role === "assistant" ? message.content.filter((content) => content.type === "toolCall") : []; + return callIds.flatMap((id) => calls.filter((call) => call.id === id).slice(0, 1)); +} +function createToolTask(tx, runtime, assistant, callId, unoffered) { + return tx.createTask(ToolTask, { kind: "model", assistant, callId, ...unoffered === void 0 ? {} : { unoffered } }, { ownership: { kind: "task", taskId: runtime.taskId } }); +} +function thresholdCompaction(view2, planned, contextWindow, policy) { + if (!policy.enabled || contextWindow <= 0) + return void 0; + const tokens = estimateContext(view2, planned.flatMap((entry2) => entry2.model ?? [])); + const blocking = contextWindow - policy.reserveTokens; + const background = blocking - policy.backgroundTokens; + const over = tokens > blocking ? "blocking" : policy.backgroundTokens > 0 && tokens > background ? "background" : void 0; + if (over === void 0 || selectCut(view2, policy.keepRecentTokens) === void 0) + return void 0; + return over; +} +function compactionFailure(outcome) { + switch (outcome.status) { + case "failed": + case "faulted": + return `Compaction failed: ${outcome.error.message}`; + case "orphaned": + return `Compaction failed: ${outcome.reason}`; + case "aborted": + return "Compaction was aborted"; + } +} +async function failModelError(runtime, text, context) { + await runtime.commit(async (tx) => { + const failure = await prepareFailure(tx, runtime); + const live = await tx.doc(LiveDoc, runtime.conversationId); + await endFailedRun(tx, runtime, live, failure, { status: "unanswered", reason: "model_error", detail: text }); + return { + status: "terminal", + outcome: { status: "failed", error: { message: text, detail: { reason: "model_error" } } } + }; + }, context); +} +async function interrupted(runtime, checkpoint, context) { + const { attempt, compacted } = checkpoint; + const policy = runtime.settings.retry; + const retry = policy.enabled && attempt <= policy.maxRetries; + const until = retry ? runtime.now() + retryDelayMs(policy, attempt) : 0; + const polled = checkpoint.phase === "poll" ? checkpoint : void 0; + const text = polled === void 0 ? `The host stopped while the model was answering, on attempt ${attempt}` : `The host stopped while the deferred answer was fetched, on attempt ${attempt}`; + if (!retry && polled !== void 0) + await cancelDeferred(runtime, polled, context); + await runtime.commit(async (tx) => { + const failure = retry ? void 0 : await prepareFailure(tx, runtime); + const live = await tx.doc(LiveDoc, runtime.conversationId); + await convertPartial(tx, live, runtime.conversationId); + if (failure === void 0) { + live.generation = { attempt, retry: { at: until, error: text } }; + const poll = polled === void 0 ? {} : { + poll: { + model: polled.model, + ...polled.thinkingLevel === void 0 ? {} : { thinkingLevel: polled.thinkingLevel }, + cutoff: polled.cutoff, + handle: polled.handle + } + }; + const next = { phase: "retry", attempt, ...compacted === void 0 ? {} : { compacted }, until, ...poll }; + return { status: "sleeping", checkpoint: next, until }; + } + await endFailedRun(tx, runtime, live, failure, { status: "unanswered", reason: "interrupted", detail: text }); + return { + status: "terminal", + outcome: { status: "failed", error: { message: text, detail: { reason: "interrupted" } } } + }; + }, context); +} +async function endCutOff2(runtime, task, context) { + const checkpoint = task.state.checkpoint; + const text = `The generation was interrupted ${cutOffCount(task)} in its ${checkpoint.phase} phase`; + const salvage = salvageable(task, runtime); + const polled = deferredOf(checkpoint); + if (salvage && polled !== void 0) + await cancelDeferred(runtime, polled, context); + await runtime.commit(async (tx) => { + const failure = await prepareFailure(tx, runtime); + const live = await tx.doc(LiveDoc, runtime.conversationId); + if (salvage) + await convertPartial(tx, live, runtime.conversationId); + await endFailedRun(tx, runtime, live, failure, { status: "unanswered", reason: "restart_limit", detail: text }); + return { + status: "terminal", + outcome: { status: "failed", error: { message: text, detail: { reason: "restart_limit" } } } + }; + }, context); +} +function deferredOf(checkpoint) { + if (checkpoint.phase === "poll") + return checkpoint; + return checkpoint.phase === "retry" ? checkpoint.poll : void 0; +} +async function cancelDeferred(runtime, checkpoint, context) { + const model2 = runtime.models.getModel(checkpoint.model.provider, checkpoint.model.modelId); + if (model2 === void 0) + return; + try { + await runtime.models.cancelDeferred(model2, checkpoint.handle, { + signal: runtime.signal, + telemetry: context.telemetry + }); + } catch (error) { + runtime.report(error, { kind: "host", callback: "models" }); + } +} +async function failNoModel(runtime, ref, context) { + const message = ref === void 0 ? "No model is configured" : `Model ${ref.provider}/${ref.modelId} is not available`; + await runtime.commit(async (tx) => { + const failure = await prepareFailure(tx, runtime); + const live = await tx.doc(LiveDoc, runtime.conversationId); + await endFailedRun(tx, runtime, live, failure, { + status: "unanswered", + reason: "no_model", + detail: message, + settlement: { status: "unanswered", reason: "no_model" } + }); + return { status: "terminal", outcome: { status: "failed", error: { message, detail: { reason: "no_model" } } } }; + }, context); +} +async function failNothingToAnswer(runtime, context) { + const message = "The conversation has nothing to answer"; + await runtime.commit(async (tx) => { + const failure = await prepareFailure(tx, runtime); + const live = await tx.doc(LiveDoc, runtime.conversationId); + await endFailedRun(tx, runtime, live, failure, { status: "unanswered", reason: "nothing_to_answer" }); + const error = { message, detail: { reason: "nothing_to_answer" } }; + return { status: "terminal", outcome: { status: "failed", error } }; + }, context); +} +async function prepareFailure(tx, runtime) { + const settings = runtime.settings; + const policy = settings.afterFailedRun; + if (policy !== "continue") + return { policy }; + return { policy, boundary: await prepareBoundary(tx, runtime.conversationId, settings) }; +} +async function endFailedRun(tx, runtime, live, failure, end) { + const conversationId = runtime.conversationId; + endRun(tx, live, runtime.taskId, end); + if (failure.policy === "withdraw") + await withdrawQueuedInputs(tx, conversationId, "run_failed"); + if (failure.boundary === void 0) + return; + const { users, first } = await applyBoundary(tx, failure.boundary, "final", runtime.now()); + if (users.length > 0) + await startRun(tx, conversationId, live, { inputs: users, first }, { keepFailure: true }); +} +async function convertPartial(tx, live, conversationId) { + const partial = live.generation?.message; + if (partial === void 0) + return; + const message = copyJson(partial); + await appendAssistant(tx, conversationId, { ...message, stopReason: "aborted" }); +} +async function providerPayload(runtime, model2, payload, context) { + let current = payload; + await runtime.hooks.each("beforeProviderRequest", async (hook2) => { + const replaced = await hook2({ model: model2, payload: current }, runtime, context); + if (replaced !== void 0) + current = replaced.payload; + }); + return current; +} +async function streamResponse(runtime, model2, messages, options, attempt, context) { + const interval = runtime.settings.progress.partialIntervalMs; + let pending; + let timer; + let inFlight; + let stopped = false; + const changes = new PartialChanges(); + const flush = () => { + timer = void 0; + const partial = pending; + pending = void 0; + if (partial === void 0 || stopped) + return; + inFlight = (async () => { + const message = copyJson(partial, { omitUndefinedProperties: true }); + const taken = changes.take(message); + try { + await runtime.commit(async (tx) => { + const live = await tx.doc(LiveDoc, runtime.conversationId); + live.generation ??= { attempt }; + changes.commit(live.generation, message, taken); + return void 0; + }, context, PROGRESS_COMMIT); + } catch (error) { + changes.restore(taken); + throw error; + } + })().catch((error) => { + if (!runtime.signal.aborted) + runtime.report(error); + }).finally(() => { + inFlight = void 0; + if (pending !== void 0 && !stopped) + timer = runtime.setTimer(flush, interval); + }); + }; + try { + const events = runtime.models.streamSimple(model2, { messages: [...messages] }, options); + for await (const event of events) { + if (event.type === "done" || event.type === "error" || event.partial.content.length === 0) + continue; + changes.observe(event); + pending = event.partial; + if (timer === void 0 && inFlight === void 0) + timer = runtime.setTimer(flush, interval); + } + return await events.result(); + } finally { + stopped = true; + timer?.(); + await inFlight; + } +} +async function classify(runtime, request2, message, context) { + runtime.signal.throwIfAborted(); + const conversationId = runtime.conversationId; + const { attempt, compacted, model: ref, thinkingLevel, cutoff } = request2; + if (thinkingLevel !== void 0) + message.thinkingLevel = thinkingLevel; + if (message.stopReason === "deferred" && message.deferred !== void 0) { + const handle = message.deferred; + const pollAt = Math.max(runtime.now() + (handle.pollAfterMs ?? DEFAULT_POLL_AFTER_MS), request2.pollAt === void 0 ? Number.NEGATIVE_INFINITY : request2.pollAt + 1); + await runtime.commit(async (tx) => { + (await tx.doc(LiveDoc, conversationId)).generation = { attempt, deferred: { pollAt } }; + const checkpoint = { + phase: "poll", + attempt, + ...compacted === void 0 ? {} : { compacted }, + model: ref, + ...thinkingLevel === void 0 ? {} : { thinkingLevel }, + cutoff, + handle, + pollAt + }; + return { status: "sleeping", checkpoint, until: pollAt }; + }, context); + return; + } + await runtime.hooks.each("afterResponse", (hook2) => hook2(message, runtime, context)); + const calls = message.content.filter((content) => content.type === "toolCall"); + if (message.stopReason === "toolUse" && calls.length > 0) { + return startToolRound(runtime, request2, message, calls, context); + } + if (message.stopReason === "stop" || message.stopReason === "length" || message.stopReason === "toolUse") { + return answer(runtime, message, context); + } + const settings = runtime.settings; + const overflow = message.stopReason === "error" && isContextOverflow(message); + const compaction = compactionPolicy(settings, ref); + if (overflow && compacted === void 0 && compaction.enabled) { + const view2 = await runtime.context(conversationId, context, { at: cutoff }); + if (selectCut(view2, compaction.keepRecentTokens) !== void 0) { + const text = message.errorMessage ?? "Context overflow"; + await runtime.commit(async (tx) => { + const live = await tx.doc(LiveDoc, conversationId); + await appendAssistant(tx, conversationId, message); + delete live.generation; + const child = await createCompaction(tx, conversationId, { reason: "overflow" }, runtime.taskId); + const checkpoint = { phase: "prepare", attempt, compacted: child, overflow: text }; + return { status: "waiting", checkpoint, on: [child], policy: "allSettled" }; + }, context); + return; + } + } + const policy = settings.retry; + const retry = message.stopReason === "error" && !overflow && isRetryableAssistantError(message) && policy.enabled && attempt <= policy.maxRetries; + const until = retry ? runtime.now() + retryDelayMs(policy, attempt) : 0; + await runtime.commit(async (tx) => { + const failure = retry ? void 0 : await prepareFailure(tx, runtime); + const live = await tx.doc(LiveDoc, conversationId); + await appendAssistant(tx, conversationId, message); + if (failure === void 0) { + live.generation = { attempt, retry: { at: until, error: message.errorMessage ?? "" } }; + const checkpoint = { + phase: "retry", + attempt, + ...compacted === void 0 ? {} : { compacted }, + until + }; + return { status: "sleeping", checkpoint, until }; + } + const text = message.errorMessage ?? `Model response ended with stop reason ${message.stopReason}`; + await endFailedRun(tx, runtime, live, failure, { status: "unanswered", reason: "model_error", detail: text }); + return { + status: "terminal", + outcome: { status: "failed", error: { message: text, detail: { reason: "model_error" } } } + }; + }, context); +} +async function answer(runtime, message, context) { + let continuation; + await runtime.hooks.each("onYield", async (hook2) => { + if (continuation !== void 0) + return; + continuation = (await hook2(message, runtime, context))?.continue; + }); + const afterRun = await asksAfterRun(runtime, context); + const conversationId = runtime.conversationId; + await runtime.commit(async (tx) => { + const boundary = await prepareBoundary(tx, conversationId, runtime.settings); + const live = await tx.doc(LiveDoc, conversationId); + const entry2 = await appendAssistant(tx, conversationId, message); + const result = { status: "terminal", outcome: { status: "completed", result: { entryId: entry2.id } } }; + const continues = takesContinuation(continuation, boundary) ? continuation : void 0; + if (continues === void 0 && afterRun) { + const held = holdRun(tx, live, runtime, { reason: "answer", answer: entry2.id, last: entry2.id }); + if (held !== void 0) + return held; + } + const { users, first } = await applyBoundary(tx, boundary, "final", runtime.now()); + if (continues !== void 0) { + const user = { role: "user", content: continues, timestamp: runtime.now() }; + await tx.appendEntry(UserEntry, conversationId, { model: [user] }); + if (live.run?.taskId === runtime.taskId) + live.run.turns = 0; + handOver(live, runtime.taskId, await createGeneration(tx, conversationId)); + delete live.generation; + return result; + } + endRun(tx, live, runtime.taskId, { status: "done", answer: entry2.id }); + if (users.length > 0) + await startRun(tx, conversationId, live, { inputs: users, first }); + return result; + }, context); +} +async function asksAfterRun(runtime, context) { + const hooks = agentHooks(await runtime.agent(context), GenerationTask.definition.name); + return hooks.some(({ handlers }) => typeof handlers.afterRun === "function"); +} +function holdRun(tx, live, runtime, end) { + const run2 = live.run; + if (run2?.taskId !== runtime.taskId) + return void 0; + for (const id of run2.inputs) + tx.settleSubmission(id, { status: "done", answer: end.answer }); + run2.inputs = []; + run2.afterRun = {}; + delete live.generation; + delete live.tools; + delete live.nestedTools; + const summary = { ...end, first: run2.first ?? end.answer }; + return { status: "running", checkpoint: { phase: "finish", run: summary } }; +} +function prepareRunEndTasks(runtime, requests, prepared) { + const rejected = []; + for (const request2 of requests) { + try { + const name = request2.task.definition.name; + if (name.startsWith("pi.")) + throw new Error(`An afterRun hook cannot start the built-in task ${name}`); + const installed = runtime.registry.task(name); + if (installed === void 0) + throw new Error(`Task ${name} is not installed`); + const input = copyJson(request2.input, { omitUndefinedProperties: true }); + const definition = installed.definition; + const checkpoint = copyJson(definition.initial(input), { omitUndefinedProperties: true }); + if (!Object.hasOwn(definition.phases, checkpoint.phase)) { + throw new Error(`Task ${name} starts at the unknown phase ${String(checkpoint.phase)}`); + } + prepared.push({ task: { definition: { ...definition, initial: () => checkpoint } }, input }); + } catch (error) { + rejected.push(error); + } + } + if (rejected.length === 1) + throw rejected[0]; + if (rejected.length > 1) + throw new AggregateError(rejected, `${rejected.length} afterRun task requests were rejected`); +} +async function endAnsweredRun(runtime, answer2, context) { + const conversationId = runtime.conversationId; + await runtime.commit(async (tx) => { + const boundary = await prepareBoundary(tx, conversationId, runtime.settings); + const live = await tx.doc(LiveDoc, conversationId); + const { users, first } = await applyBoundary(tx, boundary, "final", runtime.now()); + endRun(tx, live, runtime.taskId, { status: "done", answer: answer2 }); + if (users.length > 0) + await startRun(tx, conversationId, live, { inputs: users, first }); + return { status: "terminal", outcome: { status: "completed", result: { entryId: answer2 } } }; + }, context); +} +async function endAnsweredCutOff(runtime, task, answer2, context) { + const text = `The generation was interrupted ${cutOffCount(task)} in its ${task.state.checkpoint.phase} phase`; + await runtime.commit(async (tx) => { + const live = await tx.doc(LiveDoc, runtime.conversationId); + endRun(tx, live, runtime.taskId, { status: "done", answer: answer2 }); + const completed = { status: "terminal", outcome: { status: "completed", result: { entryId: answer2 } } }; + return endedByCrashes(completed, text); + }, context); +} +function takesContinuation(continuation, boundary) { + const items = boundary.inbox.items; + return continuation !== void 0 && !items.some((item) => item.mode === "steer" || item.mode === "followUp") && !hasQueuedReset(items); +} +async function startToolRound(runtime, request2, message, calls, context) { + const conversationId = runtime.conversationId; + const messages = request2.messages ?? (await runtime.context(conversationId, context, { at: request2.cutoff })).messages; + const offered = new Set(getCurrentTools(messages).map((tool) => tool.name)); + const tools = (await runtime.agent(context)).tools; + const sequential = runtime.settings.toolExecution === "sequential" || calls.some((call) => offered.has(call.name) && tools.find((tool) => tool.name === call.name)?.executionMode === "sequential"); + await runtime.commit(async (tx) => { + const live = await tx.doc(LiveDoc, conversationId); + const entry2 = await appendAssistant(tx, conversationId, message); + const slots = []; + const tools2 = []; + const pending = []; + for (const call of calls) { + const unoffered = offered.has(call.name) ? {} : { unoffered: true }; + if (sequential && tools2.length > 0) { + pending.push(call.id); + slots.push({ callId: call.id, name: call.name, status: "pending", ...unoffered }); + continue; + } + const taskId = await createToolTask(tx, runtime, entry2.id, call.id, unoffered.unoffered); + tools2.push(taskId); + slots.push({ callId: call.id, name: call.name, taskId, status: "pending", ...unoffered }); + } + delete live.generation; + live.tools = slots; + if (live.run?.taskId === runtime.taskId) { + live.run.turns += 1; + live.run.first ??= entry2.id; + } + const checkpoint = { phase: "tools", assistant: entry2.id, tools: tools2, pending }; + return { status: "waiting", checkpoint, on: tools2, policy: "allSettled" }; + }, context); +} +async function finishToolRound(runtime, assistant, tools, context) { + const conversationId = runtime.conversationId; + const controls = /* @__PURE__ */ new Map(); + const outcomes = await runtime.outcomes(tools, context); + tools.forEach((id, index) => { + const outcome = outcomes[index]; + controls.set(id, outcome.status === "completed" && outcome.result.kind !== "nested" ? outcome.result.control : void 0); + }); + const slots = (await runtime.snapshot(LiveDoc, conversationId, context))?.tools ?? []; + const results = slots.flatMap((slot) => slot.entry === void 0 ? [] : [slot.entry]); + await runtime.hooks.each("afterTools", (hook2) => hook2(assistant, results, runtime, context)); + const ordered = slots.map((slot) => slot.taskId === void 0 ? void 0 : controls.get(slot.taskId)); + const terminate = slots.length > 0 && ordered.every((control) => control?.terminate === true); + const added = ordered.flatMap((control) => control?.addTools ?? []); + const handoff = ordered.findLast((control) => control?.handoff !== void 0)?.handoff; + const maxTurns = (await runtime.agent(context)).maxTurns; + const afterRun = terminate && await asksAfterRun(runtime, context); + await runtime.commit(async (tx) => { + const boundary = await prepareBoundary(tx, conversationId, runtime.settings); + if (added.length > 0) + await addTools(tx, conversationId, added); + const live = await tx.doc(LiveDoc, conversationId); + const now = runtime.now(); + let last = results.reduce((newest, id) => id > newest ? id : newest, assistant); + if (handoff !== void 0) { + const message = { role: "user", content: handoff, timestamp: now }; + const entry2 = await tx.appendEntry(ResetEntry, conversationId, { head: "self", model: [message] }); + boundary.head = entry2.id; + last = entry2.id; + } + const turns = live.run?.taskId === runtime.taskId ? live.run.turns : 0; + const held = afterRun ? holdRun(tx, live, runtime, { reason: "terminate", answer: assistant, last }) : void 0; + if (held !== void 0) + return held; + if (terminate) { + const { users, first } = await applyBoundary(tx, boundary, "final", now); + endRun(tx, live, runtime.taskId, { status: "done", answer: assistant }); + if (users.length > 0) + await startRun(tx, conversationId, live, { inputs: users, first }); + } else if (maxTurns !== void 0 && turns >= maxTurns) { + const policy = runtime.settings.afterFailedRun; + const failure = { policy, ...policy === "continue" ? { boundary } : {} }; + await endFailedRun(tx, runtime, live, failure, { + status: "unanswered", + reason: "turn_limit", + detail: turns === 1 ? "1 turn" : `${turns} turns` + }); + } else { + const { users, first, reset } = await applyBoundary(tx, boundary, "postTools", now); + if (reset) { + endRun(tx, live, runtime.taskId, { status: "unanswered", reason: "reset" }); + if (users.length > 0) { + await startRun(tx, conversationId, live, { inputs: users, first }, { keepFailure: true }); + } + } else { + delete live.tools; + delete live.nestedTools; + if (live.run?.taskId === runtime.taskId) + live.run.inputs.push(...users); + handOver(live, runtime.taskId, await createGeneration(tx, conversationId)); + } + } + return { status: "terminal", outcome: { status: "completed", result: { entryId: assistant } } }; + }, context); +} +async function appendAssistant(tx, conversationId, message) { + await recordUsage(tx, conversationId, "models", `${message.provider}/${message.model}`, message.usage); + return tx.appendEntry(AssistantEntry, conversationId, { model: [message] }); +} +async function startRun(tx, conversationId, live, run2, options) { + const { inputs, first } = run2; + const taskId = await createGeneration(tx, conversationId, { submissionIds: inputs }); + live.run = { taskId, inputs, turns: 0, ...first === void 0 ? {} : { first } }; + if (options?.keepFailure !== true) + delete live.runFailure; +} +function createGeneration(tx, conversationId, telemetry = {}) { + return tx.createTask(GenerationTask, {}, { ownership: { kind: "conversation" }, conversationId, ...telemetry }); +} +function handOver(live, from, to) { + if (live.run?.taskId === from) + live.run.taskId = to; +} + +// node_modules/@earendil-works/pi-durable/dist/harness/live.js +var LiveDoc = defineDoc({ + kind: "pi.live", + version: 3, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({}), + // Version 1 named a compaction's trigger `reason`, in `compactions` and `compactionFailure`. Versions 1 and 2 (as + // builds before `run.turns` stored it) may lack `run.turns`: a run in flight across the upgrade counts its turns + // from 0. Version 2 already names the trigger `trigger`, so renaming leaves it alone. + migrate: (value2) => { + const live = value2; + const { run: run2, compactions, compactionFailure: compactionFailure2 } = live; + return { + ...value2, + ...run2 === void 0 ? {} : { run: { ...run2, turns: typeof run2.turns === "number" ? run2.turns : 0 } }, + ...compactions === void 0 ? {} : { compactions: compactions.map(renameReason) }, + ...compactionFailure2 === void 0 ? {} : { compactionFailure: renameReason(compactionFailure2) } + }; + }, + // REMINDER: a complete base whenever nothing runs (spec §8.2): no generation and no running tool slot. That holds + // while idle, in the commit handing a generation over to its tool round, and between tools, so the delta chain + // spans at most one generation or the overlapping execution of one round's tools. A slot holds output only while + // running, so every base is small; a nested call's result lives in its caller's task documents, never here. Do not + // add a delta-count bound; the tool output benchmark checks this rule. + checkpointWhen: (value2) => value2.generation === void 0 && !(value2.tools ?? []).some((slot) => slot.status === "running") && !(value2.nestedTools ?? []).some((slot) => slot.status === "running") +}); +function renameReason(value2) { + return Object.fromEntries(Object.entries(value2).map(([key, field]) => [key === "reason" ? "trigger" : key, field])); +} +var PROGRESS_COMMIT = { persistence: { kind: "deferred" } }; +var RUN_TASK_KINDS = /* @__PURE__ */ new Set(["pi.generation"]); +var TOOL_TASK_KIND = "pi.tool"; +var COMPACTION_TASK_KIND = "pi.compaction"; +var LIMITS_RESTARTS = /* @__PURE__ */ new Set([...RUN_TASK_KINDS, TOOL_TASK_KIND, COMPACTION_TASK_KIND]); +function cutOffTooOften(task, runtime) { + return task.restarts !== void 0 && task.restarts >= runtime.settings.restartLimit; +} +function salvageable(task, runtime) { + return (task.restarts ?? 0) <= runtime.settings.restartLimit; +} +function cutOffCount(task) { + const restarts = task.restarts ?? 0; + return restarts === 1 ? "once" : `${restarts} times in a row`; +} +function endRun(tx, live, taskId, end) { + if (live.run?.taskId === taskId) { + const inputs = [...live.run.inputs]; + const { first } = live.run; + if (end.status === "done") { + for (const id of inputs) + tx.settleSubmission(id, { status: "done", answer: end.answer }); + } else if (live.run.afterRun === void 0) { + const { reason, detail } = end; + const settlement = end.settlement ?? { + status: "unanswered", + reason, + ...detail === void 0 ? {} : { detail } + }; + for (const id of inputs) + tx.settleSubmission(id, settlement); + live.runFailure = { + taskId, + inputs, + reason, + ...detail === void 0 ? {} : { detail }, + ...first === void 0 ? {} : { first } + }; + } + delete live.run; + } + delete live.generation; + delete live.tools; + delete live.nestedTools; +} +function addCompactionStatus(live, status) { + live.compactions ??= []; + live.compactions.push(status); +} +function compactionStatus(live, taskId) { + return live.compactions?.find((status) => status.taskId === taskId); +} +function removeCompactionStatus(live, taskId) { + const statuses = live.compactions; + if (statuses === void 0) + return; + const index = statuses.findIndex((status) => status.taskId === taskId); + if (index >= 0) + statuses.splice(index, 1); + if (statuses.length === 0) + delete live.compactions; +} +function failCompactionStatus(live, taskId, error) { + const status = compactionStatus(live, taskId); + if (status !== void 0) + live.compactionFailure = { taskId: status.taskId, trigger: status.trigger, error }; + removeCompactionStatus(live, taskId); +} +function toolSlot(live, taskId) { + const slot = live.tools?.find((each) => each.taskId === taskId); + if (slot !== void 0 || live.nestedTools === void 0) + return slot; + const nested = live.nestedTools; + let low = 0; + let high = nested.length - 1; + while (low <= high) { + const middle = low + high >>> 1; + const candidate = nested[middle]; + if (candidate.taskId === taskId) + return candidate; + if (candidate.taskId < taskId) + low = middle + 1; + else + high = middle - 1; + } + return void 0; +} +function finishSlot(slot) { + slot.status = "done"; + clearProgress(slot); +} +function removeNestedSlots(live, taskId) { + const nested = live.nestedTools; + if (nested === void 0) + return; + const removed = /* @__PURE__ */ new Set([taskId]); + for (const slot of nested) + if (removed.has(slot.parentTaskId)) + removed.add(slot.taskId); + for (let index = nested.length - 1; index >= 0; index--) { + if (removed.has(nested[index].parentTaskId)) + nested.splice(index, 1); + } + if (nested.length === 0) + delete live.nestedTools; +} +function clearProgress(slot) { + delete slot.output; + delete slot.droppedBytes; + delete slot.droppedLines; + delete slot.details; + delete slot.diagnostics; +} +async function settleSchedulerOutcome(tx, record, outcome) { + if (record.kind === TOOL_TASK_KIND) { + const live2 = await tx.doc(LiveDoc, record.conversationId); + const slot = toolSlot(live2, record.id); + if (slot !== void 0) + finishSlot(slot); + removeNestedSlots(live2, record.id); + return; + } + const detail = outcome.status === "faulted" ? outcome.error.detail : void 0; + const cutOff = typeof detail === "object" && detail !== null && "reason" in detail && detail.reason === "restart_limit"; + if (record.kind === COMPACTION_TASK_KIND) { + const live2 = await tx.doc(LiveDoc, record.conversationId); + if (cutOff) + removeCompactionStatus(live2, record.id); + else + failCompactionStatus(live2, record.id, outcome.status === "faulted" ? outcome.error.message : outcome.reason); + return; + } + if (!RUN_TASK_KINDS.has(record.kind)) + return; + const live = await tx.doc(LiveDoc, record.conversationId); + if (live.run?.taskId !== record.id) + return; + if (!cutOff) + await convertPartial(tx, live, record.conversationId); + endRun(tx, live, record.id, outcome.status === "faulted" ? { status: "unanswered", reason: cutOff ? "aborted" : "faulted", detail: outcome.error.message } : { + status: "unanswered", + reason: "orphaned", + detail: outcome.reason, + settlement: { status: "unanswered", reason: outcome.reason } + }); +} + +// node_modules/@earendil-works/pi-durable/dist/harness/submissions.js +var Submissions = class { + #telemetry; + #session; + #now; + /** Read at each admission, on the Session line. */ + #queueModes; + /** Enable task scheduling; submitting or waiting asks for progress. */ + #resume; + #waiters = new Waiters(); + #closed = false; + constructor(session, now, queueModes, resume, telemetry = NOOP_TELEMETRY_CONTEXT) { + this.#telemetry = telemetry; + this.#session = session; + this.#now = now; + this.#queueModes = queueModes; + this.#resume = resume; + session.followCommits((publication) => this.#observe(publication)); + session.subscribeClose(() => { + this.#closed = true; + this.#waiters.rejectAll(closedError(this.#session)); + }); + } + /** Admit a submission in one commit; see `admitSubmission()`. */ + async submit(conversationId, draft, context) { + const { id } = await this.#traced(conversationId, draft, context, (span) => this.#session.commitWith((tx) => admitSubmission(tx, conversationId, draft, this.#now(), this.#queueModes(), span), withTelemetry(span, context))); + return new SubmissionHandle(id, this); + } + /** + * Admit a submission inside the caller's commit `tx`, with the rules of `submit()`. The admission is stored or lost + * with that commit. It must come before the commit's first table write, another admission's included. + */ + async admit(tx, conversationId, draft) { + if (!this.#session.ownsTransaction(tx)) + throw new Error("The transaction belongs to another Session"); + if (tx.hasTableWrite) + throw new ReadAfterWrite("submit(tx, draft)"); + const admission = await this.#traced(conversationId, draft, tx.context, (span) => admitSubmission(tx, conversationId, draft, this.#now(), this.#queueModes(), span)); + return admission.id; + } + /** Run one admission in its `pi.durable.submit` span, asking for progress first, as the run it starts needs it. */ + #traced(conversationId, draft, context, admit) { + this.#resume(); + const startsRun = draft.type !== "write"; + const parent = startsRun ? this.#telemetry : context.telemetry; + return createTypedSpanStarter(parent, [DURABLE_TELEMETRY_SCHEMA])("pi.durable.submit", { + "submission.type": draft.type, + "conversation.id": conversationId + }, async (span) => { + if (startsRun) + span.addLink({ context: context.telemetry }); + try { + const admission = await admit(span); + span.setAttributes({ "submission.id": admission.id, result: admission.status }); + return admission; + } catch (error) { + span.setStatus({ status: "error" }); + throw error; + } + }); + } + /** Handle for an existing submission, or `undefined`. */ + async get(id, context) { + const record = await this.#session.readOnLine((storage) => storage.submission(id, context)); + return record === void 0 ? void 0 : new SubmissionHandle(record.id, this); + } + async status(id, context) { + const record = await this.#session.readOnLine((storage) => storage.submission(id, context)); + if (record === void 0) + throw new Error(`Submission ${id} does not exist`); + return record; + } + async wait(id, context) { + this.#resume(); + const found = await this.#session.readOnLine(async (storage) => { + const record = await storage.submission(id, context); + if (record === void 0) + throw new Error(`Submission ${id} does not exist`); + if (isSettled(record)) + return { promise: Promise.resolve(record) }; + if (this.#closed) + throw closedError(this.#session); + return { promise: this.#waiters.add(id, context) }; + }); + return found.promise; + } + /** Withdraw a queued submission and remove its inbox item; placed inputs and settled submissions are reported. */ + abort(id, context, conversationId) { + return this.#session.commitWith(async (tx) => { + const record = await tx.submission(id); + if (record === void 0 || conversationId !== void 0 && record.conversationId !== conversationId) { + return "not_found"; + } + if (record.status === "queued") { + tx.settleSubmission(id, { status: "unanswered", reason: "aborted" }); + await removeInboxItem(tx, record.conversationId, id); + return "aborted"; + } + return record.status === "placed" ? "already_placed" : "settled"; + }, context); + } + #observe(publication) { + if (publication.kind === "memory") + return; + for (const change of publication.changes) { + if (change.type !== "submission" || !isSettled(change.value)) + continue; + this.#waiters.resolve(change.value.id, change.value); + } + } +}; +var SubmissionHandle = class { + id; + #submissions; + constructor(id, submissions) { + this.id = id; + this.#submissions = submissions; + } + status(context) { + return this.#submissions.status(this.id, context); + } + wait(context) { + return this.#submissions.wait(this.id, context); + } + async abort(context) { + const result = await this.#submissions.abort(this.id, context); + if (result === "not_found") + throw new Error(`Submission ${this.id} does not exist`); + return result; + } +}; +function isSettled(record) { + return record.status === "done" || record.status === "unanswered"; +} +function checkInputEntry(entry2) { + const { kind } = entry2; + if (typeof kind !== "string" || kind.length === 0 || kind.startsWith("pi.")) { + throw new TypeError(`An input entry's kind must be a non-empty string not starting with "pi.", got ${String(kind)}`); + } +} +async function admitSubmission(tx, conversationId, draft, now, queueModes, span) { + if (draft.type === "input" && draft.entry !== void 0) + checkInputEntry(draft.entry); + if (draft.requestId !== void 0) { + const existing = await tx.submissionByRequest(conversationId, draft.requestId); + if (existing !== void 0) { + if (existing.type !== draft.type) { + throw new Error(`Request ${draft.requestId} already identifies a submission of type ${existing.type}`); + } + return { id: existing.id, status: existing.status === "unanswered" ? "done" : existing.status }; + } + } + const fields = { conversationId, requestId: draft.requestId, trace: span?.propagation?.inject(span) }; + if (draft.type === "write" && isDisplayOnly(draft.entry) && !hasQueuedReset((await tx.doc(InboxDoc, conversationId)).items)) { + const entry3 = await tx.appendEntry(conversationId, draft.entry); + const write = { ...fields, type: "write", status: "done", entry: entry3.id }; + return { id: (await tx.createSubmission(write)).id, status: "done" }; + } + const live = await tx.doc(LiveDoc, conversationId); + const busy = live.run !== void 0; + if (draft.type === "input" && draft.whenBusy === "steer" && live.run !== void 0 && span?.propagation !== void 0) { + const run2 = await tx.task(live.run.taskId); + if (run2?.trace !== void 0) + span.addLink({ context: span.propagation.extract(run2.trace) }); + } + if (busy && draft.type === "input" && draft.whenBusy === "reject") + throw new ConversationBusy(conversationId); + if (!busy && draft.type === "input" && draft.whenIdle === "reject") + throw new ConversationIdle(conversationId); + if (draft.type === "continue") { + if (busy) + throw new ConversationBusy(conversationId); + const boundary2 = await prepareBoundary(tx, conversationId, queueModes); + const { id: id2 } = await tx.createSubmission({ ...fields, type: "continue", status: "placed" }); + const { users, first } = await applyBoundary(tx, boundary2, "final", now); + await startRun(tx, conversationId, live, { inputs: [...users, id2], first: live.runFailure?.first ?? first }); + return { id: id2, status: "placed" }; + } + const boundary = busy ? void 0 : await prepareBoundary(tx, conversationId, queueModes); + if (boundary === void 0 || boundary.inbox.items.length > 0) { + const { id: id2 } = await tx.createSubmission({ + ...fields, + type: draft.type, + status: "queued" + }); + const value2 = copyJson(draft.type === "write" ? draft.entry : draft.content, { + omitUndefinedProperties: true + }); + const items = (boundary?.inbox ?? await tx.doc(InboxDoc, conversationId)).items; + if (draft.type === "write") + items.push({ id: id2, mode: "write", entry: value2 }); + else { + const mode = draft.whenBusy === "steer" ? "steer" : "followUp"; + const content = value2; + const entry3 = draft.entry === void 0 ? {} : { entry: pickInputEntry(draft.entry) }; + items.push({ id: id2, mode, content, ...entry3 }); + } + if (boundary === void 0) + return { id: id2, status: "queued" }; + const { users, first } = await applyBoundary(tx, boundary, "final", now); + if (users.length > 0) + await startRun(tx, conversationId, live, { inputs: users, first }); + return { id: id2, status: draft.type === "write" ? "done" : users.at(-1) === id2 ? "placed" : "queued" }; + } + if (draft.type === "write") { + if (isStale(boundary, draft.entry)) { + const stale = { status: "unanswered", reason: "stale" }; + return { + id: (await tx.createSubmission({ ...fields, type: "write", ...stale })).id, + status: "done" + }; + } + const entry3 = await tx.appendEntry(conversationId, draft.entry); + const write = { ...fields, type: "write", status: "done", entry: entry3.id }; + return { id: (await tx.createSubmission(write)).id, status: "done" }; + } + const entry2 = await appendInput(tx, conversationId, draft.content, draft.entry, now); + const input = { ...fields, type: "input", status: "placed", entry: entry2.id }; + const { id } = await tx.createSubmission(input); + await startRun(tx, conversationId, live, { inputs: [id], first: entry2.id }); + return { id, status: "placed" }; +} + +// node_modules/@earendil-works/pi-durable/dist/harness/compaction.js +var TOOL_RESULT_MAX_CHARS = 2e3; +var SUMMARY_PREFIX = "The conversation history before this point was compacted into the following summary:\n\n\n"; +var SUMMARY_SUFFIX = "\n"; +var SUMMARIZATION_SYSTEM_PROMPT = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI assistant, then produce a structured summary following the exact format specified. + +Do NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`; +var SUMMARIZATION_PROMPT = `The messages above are a conversation to summarize. Create a structured context checkpoint summary that another LLM will use to continue the work. If the conversation starts with an earlier summary, preserve its information and fold the newer messages into it. + +Use this EXACT format: + +## Goal +[What is the user trying to accomplish? Can be multiple items if the session covers different tasks.] + +## Constraints & Preferences +- [Any constraints, preferences, or requirements mentioned by user] +- [Or "(none)" if none were mentioned] + +## Progress +### Done +- [x] [Completed tasks/changes] + +### In Progress +- [ ] [Current work] + +### Blocked +- [Issues preventing progress, if any] + +## Key Decisions +- **[Decision]**: [Brief rationale] + +## Next Steps +1. [Ordered list of what should happen next] + +## Critical Context +- [Any data, examples, or references needed to continue] +- [Or "(none)" if not applicable] + +Keep each section concise. Preserve exact file paths, function names, and error messages.`; +var CompactionTask = defineTask({ + name: "pi.compaction", + version: 1, + initial: () => ({ phase: "select" }), + phases: { + select: async (task, runtime, context) => { + if (cutOffTooOften(task, runtime)) + return failCutOff(runtime, task, context); + const { conversationId } = runtime; + const agent = await runtime.agent(context); + const settings = runtime.settings; + const ref = agent.model; + const model2 = ref === void 0 ? void 0 : runtime.models.getModel(ref.provider, ref.modelId); + if (ref === void 0 || model2 === void 0) + return failNoModel2(runtime, ref, context); + const policy = compactionPolicy(settings, ref); + const view2 = await runtime.context(conversationId, context); + const cut = selectCut(view2, policy.keepRecentTokens); + if (cut === void 0) + return complete(runtime, context); + const firstKept = view2.entries[cut].id; + const { reason, instructions } = task.input; + const compaction = { + reason, + entries: view2.entries.slice(0, cut), + messages: summarizedMessages(view2, cut), + firstKept, + ...instructions === void 0 ? {} : { instructions } + }; + let decision; + await runtime.hooks.each("beforeCompact", async (hook2) => { + if (decision === void 0) + decision = await hook2(compaction, runtime, context); + }); + if (decision !== void 0 && "decline" in decision) + return complete(runtime, context); + if (decision !== void 0) + return place(runtime, firstKept, decision.summary, context); + const request2 = { + attempt: 1, + model: ref, + thinkingLevel: agent.thinkingLevel, + streamOptions: settings.stream, + maxTokens: Math.min(Math.floor(0.8 * policy.reserveTokens), model2.maxTokens > 0 ? model2.maxTokens : Number.POSITIVE_INFINITY), + tail: view2.entries.reduce((tail, entry2) => entry2.id > tail ? entry2.id : tail, firstKept), + firstKept + }; + await runtime.commit(() => ({ status: "running", checkpoint: { phase: "summarize", ...request2 } }), context); + }, + summarize: async (task, runtime, context) => { + if (cutOffTooOften(task, runtime)) + return failCutOff(runtime, task, context); + const { phase: _, ...request2 } = task.state.checkpoint; + const { model: ref, thinkingLevel, streamOptions, maxTokens, tail, firstKept, attempt } = request2; + const model2 = runtime.models.getModel(ref.provider, ref.modelId); + if (model2 === void 0) + return failNoModel2(runtime, ref, context); + const view2 = await runtime.context(runtime.conversationId, context, { at: tail }); + const cut = view2.entries.findIndex((entry2) => entry2.id === firstKept); + const now = runtime.now(); + const messages = [ + { role: "system", content: SUMMARIZATION_SYSTEM_PROMPT, timestamp: now }, + { + role: "user", + content: [{ type: "text", text: summaryPrompt(summarizedMessages(view2, cut), task.input.instructions) }], + timestamp: now + } + ]; + const { deferred: _deferred, ...forwarded } = streamOptions; + const options = { + ...forwarded, + cacheRetention: "none", + maxTokens, + signal: runtime.signal, + telemetry: context.telemetry, + sessionId: await ensureProviderSessionId(runtime, context), + ...thinkingLevel === "off" ? {} : { reasoning: thinkingLevel } + }; + const message = await runtime.models.completeSimple(model2, { messages }, options); + runtime.signal.throwIfAborted(); + const summary = summaryText(message); + const policy = runtime.settings.retry; + const retry = message.stopReason === "error" && isRetryableAssistantError(message) && policy.enabled && attempt <= policy.maxRetries; + const until = retry ? runtime.now() + retryDelayMs(policy, attempt) : 0; + await runtime.commit(async (tx, current) => { + await recordUsage(tx, runtime.conversationId, "models", `${message.provider}/${message.model}`, message.usage); + const live = await tx.doc(LiveDoc, runtime.conversationId); + if (summary !== void 0) + return placeSummary(tx, runtime, current, live, firstKept, summary); + if (retry) { + const status = compactionStatus(live, runtime.taskId); + if (status !== void 0) + status.retry = { at: until, error: message.errorMessage ?? "" }; + const checkpoint = { phase: "retry", ...request2, until }; + return { status: "sleeping", checkpoint, until }; + } + const text = summaryFailure(message); + failCompactionStatus(live, runtime.taskId, text); + return { + status: "terminal", + outcome: { status: "failed", error: { message: text, detail: { reason: "model_error" } } } + }; + }, context); + }, + /** After the backoff's sleep; a run before `until` (an early wake, or a record of an earlier version) sleeps again. */ + retry: async (task, runtime, context) => { + const { phase: _, until, ...request2 } = task.state.checkpoint; + if (cutOffTooOften(task, runtime)) + return failCutOff(runtime, task, context); + if (until > runtime.now()) + return runtime.sleepUntil(until, task.state.checkpoint, context); + const attempt = request2.attempt + 1; + await runtime.commit(async (tx) => { + const status = compactionStatus(await tx.doc(LiveDoc, runtime.conversationId), runtime.taskId); + if (status !== void 0) { + status.attempt = attempt; + delete status.retry; + } + return { status: "running", checkpoint: { phase: "summarize", ...request2, attempt } }; + }, context); + } + }, + abort: async (_task, runtime, context) => { + await runtime.commit(async (tx) => { + removeCompactionStatus(await tx.doc(LiveDoc, runtime.conversationId), runtime.taskId); + return { status: "terminal", outcome: { status: "aborted" } }; + }, context); + } +}); +async function createCompaction(tx, conversationId, input, owner) { + const ownership = owner === void 0 ? { kind: "conversation" } : { kind: "task", taskId: owner }; + const background = owner === void 0 && input.reason !== "manual"; + const taskId = await tx.createTask(CompactionTask, input, { ownership, conversationId, background }); + const status = { taskId, trigger: input.reason, blocking: owner !== void 0, attempt: 1 }; + addCompactionStatus(await tx.doc(LiveDoc, conversationId), status); + return taskId; +} +function compactionPolicy(settings, model2) { + const { modelOverrides, ...policy } = settings.compaction; + const override = modelOverrides?.[`${model2.provider}/${model2.modelId}`]; + return { + enabled: override?.enabled ?? policy.enabled, + reserveTokens: override?.reserveTokens ?? policy.reserveTokens, + keepRecentTokens: override?.keepRecentTokens ?? policy.keepRecentTokens, + backgroundTokens: override?.backgroundTokens ?? policy.backgroundTokens + }; +} +function selectCut(view2, keepRecentTokens) { + const { contributions } = view2; + const start = view2.head === void 0 ? 0 : 1; + const candidates = []; + for (let index = start; index < contributions.length; index++) { + if (isCandidate(contributions, index)) + candidates.push(index); + } + let kept = 0; + let cut; + for (let index = contributions.length - 1; index >= start; index--) { + for (const message of contributions[index]) + kept += estimateMessageTokens(message); + if (kept < keepRecentTokens) + continue; + cut = candidates.find((candidate) => candidate >= index) ?? candidates.at(-1); + break; + } + if (cut === void 0) + return void 0; + for (let index = start; index < cut; index++) + if (contributions[index].length > 0) + return cut; + return void 0; +} +function isCandidate(contributions, index) { + const first = contributions[index][0]; + if (first?.role === "assistant") + return true; + if (first?.role !== "user") + return false; + let calls = /* @__PURE__ */ new Set(); + for (let before = index - 1; before >= 0; before--) { + const assistant = contributions[before].findLast((message) => message.role === "assistant"); + if (assistant === void 0) + continue; + calls = new Set(assistant.content.flatMap((content) => content.type === "toolCall" ? [content.id] : [])); + break; + } + if (calls.size === 0) + return true; + for (let after = index; after < contributions.length; after++) { + for (const [position, message] of contributions[after].entries()) { + if (message.role === "assistant" && (after > index || position > 0)) + return true; + if (message.role === "toolResult" && calls.has(message.toolCallId)) + return false; + } + } + return true; +} +function summarizedMessages(view2, cut) { + return orderToolResults(view2.contributions.slice(0, cut).flat()); +} +function estimateContext(view2, extra) { + let measured; + const after = view2.head?.id ?? Number.NEGATIVE_INFINITY; + for (let index = view2.entries.length - 1; index >= 0 && measured === void 0; index--) { + if (view2.entries[index].id <= after) + continue; + measured = view2.contributions[index].findLast((message) => message.role === "assistant" && calculateContextTokens(message.usage) > 0); + } + const from = measured === void 0 ? 0 : view2.messages.lastIndexOf(measured) + 1; + let tokens = measured === void 0 ? 0 : calculateContextTokens(measured.usage); + for (const message of view2.messages.slice(from)) + tokens += estimateMessageTokens(message); + for (const message of extra) + tokens += estimateMessageTokens(message); + return tokens; +} +function summaryText(message) { + if (message.stopReason !== "stop" || message.content.some((content) => content.type === "toolCall")) + return void 0; + const text = message.content.flatMap((content) => content.type === "text" ? [content.text] : []).join("\n").trim(); + return text.length === 0 ? void 0 : text; +} +function summaryFailure(message) { + if (message.stopReason === "error" || message.stopReason === "aborted") { + return `Summarization failed: ${message.errorMessage ?? message.stopReason}`; + } + if (message.stopReason === "length") + return "Summarization hit the token limit; the summary is incomplete"; + if (message.content.some((content) => content.type === "toolCall")) + return "Summarization attempted to call a tool"; + return "Summarization produced no text"; +} +function summaryPrompt(messages, instructions) { + const focus = instructions === void 0 ? "" : ` + +Additional focus: ${instructions}`; + return ` +${serializeConversation(messages)} + + +${SUMMARIZATION_PROMPT}${focus}`; +} +function serializeConversation(messages) { + const parts = []; + for (const message of messages) { + if (message.role === "user") { + const text = contentText2(message.content); + if (text.length > 0) + parts.push(`[User]: ${text}`); + } else if (message.role === "assistant") { + const text = message.content.flatMap((content) => content.type === "text" ? [content.text] : []); + const calls = message.content.flatMap((content) => content.type === "toolCall" ? [ + `${content.name}(${Object.entries(content.arguments).map(([key, value2]) => `${key}=${JSON.stringify(value2)}`).join(", ")})` + ] : []); + if (text.length > 0) + parts.push(`[Assistant]: ${text.join("\n")}`); + if (calls.length > 0) + parts.push(`[Assistant tool calls]: ${calls.join("; ")}`); + } else if (message.role === "toolResult") { + const text = contentText2(message.content); + if (text.length > 0) + parts.push(`[Tool result]: ${truncate(text, TOOL_RESULT_MAX_CHARS)}`); + } + } + return parts.join("\n\n"); +} +function contentText2(content) { + if (typeof content === "string") + return content; + return content.flatMap((block) => block.type === "text" && block.text !== void 0 ? [block.text] : []).join("\n"); +} +function truncate(text, maxChars) { + if (text.length <= maxChars) + return text; + return `${text.slice(0, maxChars)} + +[... ${text.length - maxChars} more characters truncated]`; +} +async function place(runtime, firstKept, summary, context) { + await runtime.commit(async (tx, current) => placeSummary(tx, runtime, current, await tx.doc(LiveDoc, runtime.conversationId), firstKept, summary), context); +} +async function placeSummary(tx, runtime, current, live, firstKept, summary) { + removeCompactionStatus(live, runtime.taskId); + delete live.compactionFailure; + const text = `${SUMMARY_PREFIX}${summary}${SUMMARY_SUFFIX}`; + const entry2 = { + kind: CompactionEntry.kind, + head: firstKept, + model: [{ role: "user", content: [{ type: "text", text }], timestamp: runtime.now() }], + data: { reason: current.input.reason } + }; + const result = current.owner === void 0 ? { + submissionId: (await admitSubmission(tx, runtime.conversationId, { type: "write", requestId: `compaction:${runtime.taskId}`, entry: entry2 }, runtime.now(), runtime.settings)).id + } : { entryId: (await tx.appendEntry(runtime.conversationId, entry2)).id }; + return { status: "terminal", outcome: { status: "completed", result } }; +} +async function complete(runtime, context) { + await runtime.commit(async (tx) => { + removeCompactionStatus(await tx.doc(LiveDoc, runtime.conversationId), runtime.taskId); + return { status: "terminal", outcome: { status: "completed", result: {} } }; + }, context); +} +async function failCutOff(runtime, task, context) { + const message = `Compaction was interrupted ${cutOffCount(task)}`; + await runtime.commit(async (tx) => { + failCompactionStatus(await tx.doc(LiveDoc, runtime.conversationId), runtime.taskId, message); + return { + status: "terminal", + outcome: { status: "failed", error: { message, detail: { reason: "restart_limit" } } } + }; + }, context); +} +async function failNoModel2(runtime, ref, context) { + const message = ref === void 0 ? "No model is configured" : `Model ${ref.provider}/${ref.modelId} is not available`; + await runtime.commit(async (tx) => { + failCompactionStatus(await tx.doc(LiveDoc, runtime.conversationId), runtime.taskId, message); + return { status: "terminal", outcome: { status: "failed", error: { message, detail: { reason: "no_model" } } } }; + }, context); +} + +// node_modules/@earendil-works/pi-durable/dist/harness/define.js +function defineExtension(extension) { + return extension; +} + +// node_modules/@earendil-works/pi-durable/dist/harness/registry.js +var SECTION_KEY = /^[a-z][a-z0-9_-]*$/; +var BUILTIN_TASKS = [GenerationTask, ToolTask, CompactionTask]; +var RegistryState = class { + #extensions; + #byName; + #tasks; + constructor(extensions) { + this.#extensions = extensions; + this.#byName = new Map(extensions.map((extension) => [extension.name, extension])); + const tasks = /* @__PURE__ */ new Map(); + for (const task of BUILTIN_TASKS) + tasks.set(task.definition.name, task); + for (const extension of extensions) { + for (const task of extension.tasks ?? []) { + const name = task.definition.name; + if (tasks.has(name)) + throw new Error(`Task ${name} of extension ${extension.name} is already installed`); + tasks.set(name, task); + } + } + this.#tasks = tasks; + } + installed() { + return this.#extensions; + } + extension(name) { + return this.#byName.get(name); + } + tools() { + return this.#extensions.flatMap((extension) => (extension.tools ?? []).map((tool) => ({ extension, tool }))); + } + sections() { + return this.#extensions.flatMap((extension) => (extension.sections ?? []).map((section2) => ({ extension, section: section2 }))); + } + tasks() { + return [...this.#tasks.values()]; + } + task(name) { + return this.#tasks.get(name); + } +}; +var RegistryImpl = class { + #current = new RegistryState([]); + #listeners = /* @__PURE__ */ new Set(); + snapshot() { + return this.#current; + } + subscribe(listener) { + this.#listeners.add(listener); + return () => this.#listeners.delete(listener); + } + install(extension) { + validateExtension(extension); + const current = this.#current.installed(); + const index = current.findIndex((installed) => installed.name === extension.name); + const next = index < 0 ? [...current, extension] : current.map((installed, at) => at === index ? extension : installed); + this.#publish(next); + } + uninstall(extension) { + const current = this.#current.installed(); + if (!current.some((installed) => installed.name === extension.name)) + return; + this.#publish(current.filter((installed) => installed.name !== extension.name)); + } + /** Build and validate the next state, which throws on a task name collision, then publish it synchronously. */ + #publish(extensions) { + this.#current = new RegistryState(extensions); + for (const listener of [...this.#listeners]) + listener(); + } +}; +function validateExtension(extension) { + const tools = /* @__PURE__ */ new Set(); + for (const tool of extension.tools ?? []) { + if (tools.has(tool.name)) + throw new Error(`Extension ${extension.name} has two tools named ${tool.name}`); + tools.add(tool.name); + } + const sections = /* @__PURE__ */ new Set(); + for (const { key } of extension.sections ?? []) { + if (!SECTION_KEY.test(key)) + throw new TypeError(`Section key ${JSON.stringify(key)} must match ${SECTION_KEY}`); + if (key === INSTRUCTIONS_KEY) + throw new Error(`Section key ${key} is reserved for the agent's instructions`); + if (sections.has(key)) + throw new Error(`Extension ${extension.name} has two sections with key ${key}`); + sections.add(key); + } +} +function createRegistry() { + return new RegistryImpl(); +} + +// node_modules/@earendil-works/pi-durable/dist/harness/task-graph.js +var LIVE_STATUSES2 = ["pending", "running", "waiting", "sleeping", "completing"]; +var SCAN_PAGE_SIZE4 = 256; +var TaskGraphView = class { + #session; + #blocking; + #mount; + #closed = false; + constructor(session, blocking) { + this.#session = session; + this.#blocking = blocking; + session.followCommits((publication, context) => { + if (this.#mount === void 0 || publication.kind === "memory") + return; + advance(this.#mount, publication, context, blocking.blocked, (error) => session.report(error)); + }); + blocking.subscribeBlocked(() => this.#refreshBlocked()); + session.subscribeClose(() => { + this.#closed = true; + const ends = closeEnds(this.#session.failure); + for (const observer of [...this.#mount?.observers ?? []]) { + contained(() => observer.end(closeEndOf(observer, ends)), (error) => session.report(error)); + } + this.#mount = void 0; + }); + } + /** + * Attach a synchronous observer of the graph (`Harness.observeTaskGraph()`), behind `guardObserver()`; `context` + * governs only the attachment. + */ + async observe(observer, context) { + let value2; + const attached = await this.#attach((current, release) => { + value2 = current; + return guardObserver(observer, release, (error) => this.#session.report(error)); + }, context); + const signal = context.abortSignal; + if (signal?.aborted) { + attached.detach(); + throw signal.reason; + } + return observation(value2, attached.observer); + } + /** A serialized watch of the graph, an observer of its mount; aborting `context` ends it `aborted`. */ + async watch(context) { + const { observer } = await this.#attach((value2, release) => new Watch(value2, release, (error) => this.#session.report(error)), context); + const signal = context.abortSignal; + if (signal?.aborted) { + observer.abort(); + throw signal.reason; + } + if (signal !== void 0) + observer.observeAbort(signal); + return observer; + } + /** Register an observer created from the current revision, atomically on the Session line. */ + #attach(create, context) { + return this.#session.readOnLine(async (storage) => { + const mount = this.#mount ?? { + ...await this.#build(storage, context), + observers: /* @__PURE__ */ new Set() + }; + const detach = () => { + mount.observers.delete(observer); + if (mount.observers.size === 0 && this.#mount === mount) + this.#mount = void 0; + }; + const observer = create(mount.value, detach); + if (this.#closed) + throw closedError(this.#session); + context.abortSignal?.throwIfAborted(); + this.#mount = mount; + mount.observers.add(observer); + return { observer, detach }; + }); + } + /** On the Session line: derive every node's blocked reason again, and publish the ones that changed. */ + #refreshBlocked() { + if (this.#mount === void 0 || this.#closed) + return; + this.#session.readOnLine(async () => { + const mount = this.#mount; + if (mount === void 0) + return; + const ops = []; + for (const [key, record] of mount.records) { + const blocked = this.#blocking.blocked(record); + if (blocked === mount.value.tasks[key]?.blocked) + continue; + ops.push(blocked === void 0 ? ["d", ["tasks", key, "blocked"]] : ["s", ["tasks", key, "blocked"], blocked]); + } + publish(mount, ops, BACKGROUND_CONTEXT, (error) => this.#session.report(error)); + }).catch(() => { + }); + } + /** Read the graph on the line, through the line's `storage`. */ + async #build(storage, context) { + const tasks = {}; + const live = /* @__PURE__ */ new Map(); + const records = []; + for (const status of LIVE_STATUSES2) { + records.push(...await scanAll((cursor) => storage.scanTasks({ status }, SCAN_PAGE_SIZE4, cursor, context))); + } + records.sort((a, b) => a.id - b.id); + for (const record of records) { + const owned = await scanAll((cursor) => storage.scanConversations({ ownerTaskId: record.id }, SCAN_PAGE_SIZE4, cursor, context)); + const conversations = owned.map((conversation) => conversation.id).sort((a, b) => a - b); + const subject = blockedSubject(record); + tasks[String(record.id)] = nodeOf2(record, conversations, this.#blocking.blocked(subject)); + live.set(String(record.id), subject); + } + return { value: { tasks }, records: live }; + } +}; +function advance(mount, publication, context, blocked, report2) { + const ops = []; + const changed = /* @__PURE__ */ new Map(); + const node = (key) => changed.has(key) ? changed.get(key) : mount.value.tasks[key]; + for (const change of publication.changes) { + if (change.type !== "task") + continue; + const record = change.value; + const key = String(record.id); + const previous = node(key); + if (record.state.status === "terminal") { + mount.records.delete(key); + if (previous === void 0) + continue; + ops.push(["d", ["tasks", key]]); + changed.set(key, void 0); + continue; + } + const subject = blockedSubject(record); + mount.records.set(key, subject); + const next = nodeOf2(record, previous?.conversations ?? [], blocked(subject)); + if (previous !== void 0 && JSON.stringify(next) === JSON.stringify(previous)) + continue; + ops.push(["s", ["tasks", key], next]); + changed.set(key, next); + } + const created = /* @__PURE__ */ new Map(); + for (const change of publication.changes) { + if (change.type !== "conversation" || change.value.owner === void 0) + continue; + const key = String(change.value.owner.taskId); + if (node(key) !== void 0) + created.set(key, [...created.get(key) ?? [], change.value.id]); + } + for (const [key, ids] of created) { + const conversations = [...node(key).conversations, ...ids].sort((a, b) => a - b); + ops.push(["s", ["tasks", key, "conversations"], conversations]); + } + publish(mount, ops, context, report2); +} +function publish(mount, ops, context, report2) { + if (ops.length === 0) + return; + mount.value = applyImmutable(mount.value, ops); + const frameContext = withoutAbortSignal(context); + const call = { kind: "value", value: mount.value, ops, retired: false }; + for (const observer of [...mount.observers]) + contained(() => observer.advance(call, frameContext), report2); +} +function nodeOf2(record, conversations, blocked) { + return { + id: record.id, + kind: record.kind, + conversationId: record.conversationId, + ...record.owner === void 0 ? {} : { owner: record.owner }, + background: record.background, + abortRequested: record.abortRequested, + state: stateOf(record), + conversations, + ...blocked === void 0 ? {} : { blocked } + }; +} +function stateOf(record) { + const state = record.state; + switch (state.status) { + case "pending": + case "running": + return { status: state.status, phase: phaseOf(state.checkpoint) }; + case "waiting": + return { status: "waiting", phase: phaseOf(state.checkpoint), on: [...state.on], policy: state.policy }; + case "sleeping": + return { status: "sleeping", phase: phaseOf(state.checkpoint), until: state.until }; + // Terminal records never reach here: they leave the graph. + case "completing": + case "terminal": + return { status: "completing", outcome: state.outcome.status }; + } +} +function phaseOf(checkpoint) { + return checkpoint.phase; +} + +// node_modules/@earendil-works/pi-durable/dist/harness/view.js +var DEFAULT_WINDOW_MIN = 50; +var MOUNTED = [ + AgentDoc, + LiveDoc, + InboxDoc, + ProviderDoc, + UsageDoc +]; +var MOUNTED_KINDS = new Set(MOUNTED.map((token) => token.definition.kind)); +var SCAN_PAGE_SIZE5 = 256; +var VIEWS = /* @__PURE__ */ new WeakMap(); +function resolveWindow(window) { + const min = window?.min ?? DEFAULT_WINDOW_MIN; + if (!Number.isSafeInteger(min) || min < 1) + throw new RangeError(`Window min must be an integer >= 1, got ${min}`); + const max = window?.max ?? 2 * min; + if (!Number.isSafeInteger(max) || max < min) { + throw new RangeError(`Window max must be an integer >= min (${min}), got ${max}`); + } + const from = window?.from; + if (from !== void 0 && !Number.isSafeInteger(from)) { + throw new RangeError(`Window from must be an entry ID, got ${from}`); + } + return { from, min, max }; +} +var ConversationViews = class { + #session; + #mounts = /* @__PURE__ */ new Map(); + #closed = false; + constructor(session) { + this.#session = session; + VIEWS.set(session, this); + session.followCommits((publication, context) => { + for (const [id, mount] of this.#mounts) + advance2(id, mount, publication, context, (error) => this.report(error)); + }); + session.subscribeClose(() => { + this.#closed = true; + const ends = closeEnds(this.#session.failure); + for (const mount of this.#mounts.values()) + for (const windowed of [...mount.observers]) { + contained(() => windowed.observer.end(closeEndOf(windowed.observer, ends)), (error) => this.report(error)); + } + this.#mounts.clear(); + }); + } + /** Report an observer's listener error through the Harness. */ + report(error) { + this.#session.report(error); + } + /** + * Attach a synchronous observer of the view (`Harness.observeConversation()`), behind `guardObserver()`; `context` + * governs only the attachment. + */ + async observe(id, observer, context, window) { + let value2; + const attached = await this.attach(id, window, (current, release) => { + value2 = current; + return guardObserver(observer, release, (error) => this.report(error)); + }, context); + const signal = context.abortSignal; + if (signal?.aborted) { + attached.detach(); + throw signal.reason; + } + return observation(value2, attached.observer); + } + /** A serialized watch of the view, an observer of its mount; aborting `context` ends it `aborted`. */ + async watch(id, context, window) { + const { observer } = await this.attach(id, window, (value2, release) => new Watch(value2, release, (error) => this.#session.report(error)), context); + const signal = context.abortSignal; + if (signal?.aborted) { + observer.abort(); + throw signal.reason; + } + if (signal !== void 0) + observer.observeAbort(signal); + return observer; + } + /** + * Register an observer created from its window's first revision, atomically on the Session line: it sees every later + * publication and nothing earlier. `release` drops it, and the mount with its last observer. + */ + async attach(id, window, create, context) { + const bounds = resolveWindow(window); + return this.#session.readOnLine(async (storage) => { + const mount = this.#mounts.get(id) ?? await this.#build(storage, id, context); + const { entries: entries2, before } = await loadWindow(storage, id, bounds, context); + const value2 = view(mount.conversation, entries2, before, mount.docs); + let windowed; + const detach = () => { + if (windowed !== void 0) + mount.observers.delete(windowed); + if (mount.observers.size === 0 && this.#mounts.get(id) === mount) + this.#mounts.delete(id); + }; + const observer = create(value2, detach); + if (this.#closed) + throw closedError(this.#session); + context.abortSignal?.throwIfAborted(); + windowed = { min: bounds.min, max: bounds.max, value: value2, observer }; + this.#mounts.set(id, mount); + mount.observers.add(windowed); + return { observer, detach }; + }); + } + /** Hydrate a mount on the line, through the line's `storage`. */ + async #build(storage, id, context) { + const conversation = await storage.conversation(id, context); + if (conversation === void 0) + throw new Error(`Conversation ${id} does not exist`); + const docs = {}; + const incarnations = /* @__PURE__ */ new Map(); + for (const token of MOUNTED) { + const loaded = await this.#session.conversationDocumentOnLine(token, id, context); + if (loaded === void 0) + continue; + docs[token.definition.kind] = loaded.value; + incarnations.set(token.definition.kind, { id: loaded.record.id, version: loaded.version }); + } + return { conversation, docs, incarnations, observers: /* @__PURE__ */ new Set() }; + } +}; +function view(conversation, entries2, before, docs) { + return before === void 0 ? { conversation, entries: entries2, docs } : { conversation, entries: entries2, before, docs }; +} +async function loadWindow(storage, conversationId, bounds, context) { + const { from, min, max } = bounds; + if (from !== void 0) { + const since = await scanUpTo(storage, { conversationId, minEntryId: from, order: "ascending" }, max + 1, context); + if (since.length <= max) { + const query = { conversationId, maxEntryId: idFromNumber(from - 1) }; + const previous = (await storage.scanEntries(query, 1, void 0, context)).items[0]; + return { entries: since, before: previous?.id }; + } + } + const newest = await scanUpTo(storage, { conversationId }, min + 1, context); + const before = newest.length > min ? newest.pop().id : void 0; + return { entries: newest.reverse(), before }; +} +async function scanUpTo(storage, query, limit, context) { + const entries2 = []; + let cursor; + do { + const page2 = await storage.scanEntries(query, Math.min(SCAN_PAGE_SIZE5, limit - entries2.length), cursor, context); + entries2.push(...page2.items); + cursor = page2.next; + } while (cursor !== void 0 && entries2.length < limit); + return entries2; +} +function advance2(id, mount, publication, context, report2) { + const docOps = []; + const appended = []; + for (const change of publication.changes) { + if (change.type === "entry" && change.value.conversationId === id) { + appended.push(change.value); + continue; + } + if (change.type !== "document" || change.conversationId !== id) + continue; + const kind = change.record.kind; + if (!MOUNTED_KINDS.has(kind) || change.record.key !== void 0) + continue; + const path = ["docs", kind]; + const mounted = mount.incarnations.get(kind); + if (change.kind === "retire") { + if (mounted?.id !== change.record.id) + continue; + mount.incarnations.delete(kind); + docOps.push(["d", path]); + } else if (mounted?.id === change.record.id && mounted.version === change.version) { + for (const op2 of change.ops) + docOps.push(prefixed(op2, path)); + } else { + mount.incarnations.set(kind, { id: change.record.id, version: change.version }); + docOps.push(["s", path, change.value]); + } + } + if (docOps.length === 0 && appended.length === 0) + return; + if (docOps.length > 0) + mount.docs = applyImmutable({ docs: mount.docs }, docOps).docs; + const frameContext = withoutAbortSignal(context); + const inserted = appended; + for (const windowed of [...mount.observers]) { + const previous = windowed.value; + let entries2 = previous.entries; + let before = previous.before; + let ops = docOps; + if (appended.length > 0) { + ops = [...docOps, ["p", ["entries"], entries2.length, 0, inserted]]; + entries2 = entries2.concat(appended); + if (entries2.length > windowed.max) { + const drop = entries2.length - windowed.min; + before = entries2[drop - 1].id; + entries2 = entries2.slice(drop); + ops.push(["p", ["entries"], 0, drop, []], ["s", ["before"], before]); + } + } + windowed.value = view(mount.conversation, entries2, before, mount.docs); + const call = { kind: "value", value: windowed.value, ops, retired: false }; + contained(() => windowed.observer.advance(call, frameContext), report2); + } +} +function prefixed(op2, prefix) { + const at = (path) => [...prefix, ...path]; + switch (op2[0]) { + case "r": + return ["s", prefix, op2[1]]; + case "p": + return ["p", at(op2[1]), op2[2], op2[3], op2[4]]; + case "m": + return ["m", at(op2[1]), op2[2]]; + case "s": + return ["s", at(op2[1]), op2[2]]; + case "d": + return ["d", at(op2[1])]; + case "a": + return ["a", at(op2[1]), op2[2]]; + case "t": + return ["t", at(op2[1]), op2[2]]; + } +} + +// node_modules/@earendil-works/pi-durable/dist/harness/harness.js +var SCAN_PAGE_SIZE6 = 256; +var SCHEDULER_INDEX_SIZES = /* @__PURE__ */ Symbol.for("pi-durable.schedulerIndexSizes"); +var SCHEDULER_IDLE_STATE = /* @__PURE__ */ Symbol.for("pi-durable.schedulerIdleState"); +var ConversationImpl = class { + id; + #host; + constructor(id, host) { + this.id = id; + this.#host = host; + } + agent(context) { + return this.#host.harness.resolveAgent(this.id, void 0, context); + } + configure(change, context) { + return this.#host.harness.commitWith((tx) => configure(tx, this.id, change), context); + } + submit(first, second) { + if ("type" in first) + return this.#host.submissions.submit(this.id, first, second); + return this.#host.submissions.admit(first, this.id, second); + } + async compact(instructions, context) { + this.#host.tasks.resume(); + const input = { reason: "manual", ...instructions === void 0 ? {} : { instructions } }; + return this.#host.harness.commitWith((tx) => createCompaction(tx, this.id, input), context); + } + async reset(handoff, context) { + const model2 = handoff === void 0 ? {} : { model: [{ role: "user", content: handoff, timestamp: this.#host.now() }] }; + const entry2 = { kind: ResetEntry.kind, head: "self", ...model2 }; + await this.#host.submissions.submit(this.id, { type: "write", entry: entry2 }, context); + } + commit(change, context, options) { + return this.#host.harness.commitWith(change, context, { conversationId: this.id }, options); + } + context(context, options) { + return readContext(this.#host.harness, this.#host.storage, this.id, context, options?.at); + } + entries(query, limit, cursor, context) { + const scan = conversationEntries(this.id, query); + return this.#host.harness.readOnLine((storage) => storage.scanEntries(scan, limit, cursor, context)); + } + fork(at, options, context) { + return this.#host.create({ kind: "fork", parentId: this.id, at, ownership: options.ownership }, options, context); + } + async abort(context, options) { + this.#host.tasks.resume(); + return this.#host.tasks.abortConversation(this.id, options?.background === true, context); + } + async waitForIdle(context) { + this.#host.tasks.resume(); + return this.#host.tasks.waitForIdle(this.id, context); + } + watch(context, window) { + return this.#host.views.watch(this.id, context, window); + } +}; +var DEFAULT_HARNESS_IDENTITY = { attribution: PI_ATTRIBUTION }; +function currentModels(models2, identity) { + const merged = mergeClientIdentity(DEFAULT_HARNESS_IDENTITY, identity) ?? DEFAULT_HARNESS_IDENTITY; + if (typeof models2 === "function") + return () => withClientIdentity(models2(), merged); + const wrapped = withClientIdentity(models2, merged); + return () => wrapped; +} +function currentSettings(settings) { + return typeof settings === "function" ? settings : () => settings; +} +var HarnessImpl = class extends SessionImpl { + #options; + #hostSettings; + #report; + #host; + #tasks; + #submissions; + #taskGraph; + constructor(rawStorage, options, context) { + const report2 = safeReport(options.onReport, options.telemetry ?? NOOP_TELEMETRY_CONTEXT); + const now = safeNow(options.now, report2); + const hostSettings = currentSettings(options.settings); + super(rawStorage, now, () => hostSettings()?.documentRetentionMs, options.setTimer, options.readOnly === true, () => hostSettings()?.progress?.persistWithinMs); + const storage = this.storage; + this.#options = options; + this.#report = report2; + this.#hostSettings = hostSettings; + const settings = () => resolveSettings(hostSettings()); + this.#tasks = new TaskScheduler({ + telemetry: options.telemetry, + session: this, + storage, + registry: options.registry, + models: currentModels(options.models, options.identity), + agent: (id, snapshot, callContext) => this.resolveAgent(id, snapshot, callContext), + settings, + env: (id, callContext) => this.buildEnv(id, callContext), + now, + onWake: options.onWake, + timers: hostTimers(options.setTimer, (error) => report2(error, { kind: "host_error", callback: "setTimer" })), + writeAtClose: (writes) => this.writeAtClose(writes), + report: this.#report, + limitsRestarts: (kind) => LIMITS_RESTARTS.has(kind), + settleOutcome: settleSchedulerOutcome, + withdrawInputs: withdrawQueuedInputs, + conversation: async (id, binding, callContext) => { + const record = await this.readOnLine((line) => line.conversation(id, callContext)); + return record === void 0 ? void 0 : boundConversation(id, binding, this.#submissions, this.#tasks); + }, + context: withoutAbortSignal(context), + readOnly: options.readOnly === true + }); + this.#submissions = new Submissions(this, now, settings, () => this.#tasks.resume(), options.telemetry); + this.#taskGraph = new TaskGraphView(this, { + blocked: (record) => this.#tasks.blockedReason(record), + subscribeBlocked: (listener) => this.#tasks.subscribeBlocked(listener) + }); + this.#host = { + harness: this, + storage, + tasks: this.#tasks, + submissions: this.#submissions, + views: new ConversationViews(this), + now, + create: (target, createOptions, context2) => this.#create(target, createOptions, context2) + }; + } + /** Resolve a conversation's committed `pi.agent` against `snapshot`, or the current one, and the current settings. */ + async resolveAgent(id, snapshot, context) { + const registry2 = snapshot ?? this.#options.registry.snapshot(); + const state = await this.snapshot(AgentDoc, id, context); + return resolveAgent(state, registry2, resolveSettings(this.#hostSettings()), (error, extension) => this.#report(error, { kind: "extension_error", conversationId: id, extension }, context)); + } + /** Build a conversation's environment from its current `cwd`; `undefined` without an `env` option. */ + async buildEnv(id, context) { + const build = this.#options.env; + if (build === void 0) + return void 0; + const cwd = (await this.snapshot(AgentDoc, id, context))?.cwd; + return build({ conversationId: id, ...cwd === void 0 ? {} : { cwd }, read: this }, context); + } + /** Reconcile surviving `running` tasks to `pending`; part of open. */ + openTasks(context) { + return this.#tasks.open(context); + } + resume() { + this.assertUsable(); + this.#tasks.resume(); + } + wake() { + this.assertUsable(); + return this.#tasks.wake(); + } + getTask(id, context) { + return this.readOnLine((storage) => storage.task(id, context)); + } + /** Internal, for tests: sizes of the scheduler's ownership indexes. */ + get [SCHEDULER_INDEX_SIZES]() { + return this.#tasks.indexSizes; + } + /** Internal, for tests: the kept contexts' idle state and its disagreements with a full recompute. */ + get [SCHEDULER_IDLE_STATE]() { + return this.#tasks.idleState; + } + inspect(context) { + return this.readOnLine(async (storage) => { + const { scheduling, tasks } = await this.#tasks.inspect(this.#options.registry.snapshot()); + const scan = (status) => scanAll((cursor) => storage.scanSubmissions({ status }, SCAN_PAGE_SIZE6, cursor, context)); + const submissions = [...await scan("queued"), ...await scan("placed")].sort((a, b) => a.id - b.id); + return { scheduling, tasks, submissions }; + }); + } + submission(id, context) { + return this.#submissions.get(id, context); + } + abortSubmission(id, context, conversationId) { + return this.#submissions.abort(id, context, conversationId); + } + abortTask(id, context) { + return this.#tasks.abort(id, context); + } + async waitForTask(id, context) { + this.#tasks.resume(); + return this.#tasks.waitForTask(id, context); + } + async waitForIdle(context) { + this.#tasks.resume(); + return this.#tasks.waitForIdle(void 0, context); + } + /** Sum every conversation's committed `pi.usage`. Each document is read at its own point; totals only grow. */ + async usage(context) { + const conversations = await this.readOnLine((storage) => scanAll((cursor) => storage.scanConversations({}, SCAN_PAGE_SIZE6, cursor, context))); + const total = UsageDoc.definition.initial(); + for (const { id } of conversations) { + const state = await this.snapshot(UsageDoc, id, context); + if (state !== void 0) + addUsageState(total, state); + } + return total; + } + watchTaskGraph(context) { + return this.#taskGraph.watch(context); + } + async observeTaskGraph(observer, context) { + this.assertUsable(); + return this.#taskGraph.observe(observer, context); + } + async observeConversation(id, observer, context, window) { + this.assertUsable(); + return this.#host.views.observe(id, observer, context, window); + } + root(context, options) { + return this.#create({ kind: "root" }, options ?? {}, context); + } + async conversation(id, context) { + this.assertUsable(); + const record = await this.readOnLine((storage) => storage.conversation(id, context)); + return record === void 0 ? void 0 : new ConversationImpl(record.id, this.#host); + } + createConversation(options, context) { + return this.#create({ kind: "independent", ownership: options.ownership }, options, context); + } + report(error, info = { kind: "listener_error" }, context) { + this.#report(error, info, context); + } + /** The ownership memberships a commit's task changes write, from the scheduler's index. */ + membershipKeys(tx) { + return this.#tasks.membershipKeys(tx); + } + /** Signal and join task invocations after the close listeners and before Storage closes; writes no task outcome. */ + beforeClose() { + return this.#tasks.join(); + } + async #create(target, options, context) { + this.assertUsable(); + const id = await this.commitWith(async (tx) => { + if (target.kind === "root" && await tx.conversation(ROOT_CONVERSATION_ID) !== void 0) { + return ROOT_CONVERSATION_ID; + } + const record = target.kind === "root" ? await tx.createRootConversation() : target.kind === "fork" ? await tx.forkConversation(target.parentId, target.at, { ownership: target.ownership }) : await tx.createConversation({ ownership: target.ownership }); + if (options.agent !== void 0) + await configure(tx, record.id, options.agent); + if (options.init !== void 0) + await options.init(tx, record.id); + return record.id; + }, context); + return new ConversationImpl(id, this.#host); + } + /** + * The built-in creation hook, in every commit that creates or forks a conversation: empty `pi.live`, `pi.inbox`, and + * `pi.usage`, a fresh `pi.provider`, the conversation's `pi.agent` (see `createAgent()`), then + * `HarnessOptions.conversationCreated`. + */ + async conversationCreated(tx, record) { + await tx.doc(LiveDoc, record.id); + await tx.doc(InboxDoc, record.id); + await tx.doc(UsageDoc, record.id); + await tx.doc(ProviderDoc, record.id); + await createAgent(tx, record); + await this.#options.conversationCreated?.(tx, record); + } +}; +function safeReport(onReport, telemetry) { + const reports = createTypedMetrics(telemetry.metrics ?? NOOP_TELEMETRY_METRICS, [DURABLE_TELEMETRY_SCHEMA]).counter("pi.durable.reports"); + return (error, info, context) => { + if (onReport !== void 0) { + contained(() => onReport({ ...info, error }), () => { + }); + } + const attributes = { + type: info.kind + }; + switch (info.kind) { + case "task_faulted": + case "task_interrupted": + case "task_outdated": + attributes.reason = info.reason; + attributes.extension = info.extension; + attributes["task.id"] = info.task.id; + break; + case "migration_failed": + case "task_error": + case "extension_error": + attributes.extension = info.extension; + attributes["task.id"] = info.task?.id; + break; + case "host_error": + attributes["task.id"] = info.task?.id; + break; + } + try { + reports.add(1, { type: info.kind }); + context?.telemetry.addEvent("pi.durable.report", attributes); + } catch { + } + }; +} +function safeNow(now, report2) { + if (now === void 0) + return Date.now; + let reported = false; + return () => { + try { + return now(); + } catch (error) { + if (!reported) { + reported = true; + report2(error, { kind: "host_error", callback: "now" }); + } + return Date.now(); + } + }; +} +function boundConversation(id, binding, submissions, tasks) { + const bind = (context) => withAbortSignal(binding.signal, context); + const bound = (operation) => { + return async (context) => { + binding.check(); + return operation(bind(context)); + }; + }; + async function submit(first, second) { + binding.check(); + if (!("type" in first)) { + binding.signal.throwIfAborted(); + return submissions.admit(first, id, second); + } + const submission2 = await submissions.submit(id, first, bind(second)); + return { + id: submission2.id, + status: bound((callContext) => submission2.status(callContext)), + wait: bound((callContext) => submission2.wait(callContext)), + abort: bound((callContext) => submission2.abort(callContext)) + }; + } + return { + id, + submit, + abort: async (context, options) => { + binding.check(); + return tasks.abortConversation(id, options?.background === true, bind(context)); + }, + waitForIdle: bound((callContext) => tasks.waitForIdle(id, callContext)) + }; +} +var Harness = { + /** Open a Harness over storage. The registry may keep changing while the Harness runs. */ + async open(storage, options, context) { + context.abortSignal?.throwIfAborted(); + const snapshot = options.registry.snapshot(); + const missing = BUILTIN_TASKS.filter((task) => snapshot.task(task.definition.name) === void 0); + if (missing.length > 0) { + const names2 = missing.map((task) => task.definition.name).join(", "); + throw new Error(`Registry lacks built-in tasks ${names2}; create it with createRegistry()`); + } + const harness2 = new HarnessImpl(storage, options, context); + try { + await harness2.openTasks(context); + } catch (error) { + await harness2.close(withoutAbortSignal(context)).catch(() => { + }); + throw error; + } + return harness2; + } +}; + +// node_modules/@earendil-works/pi-durable/dist/storage/scan.js +function scanStart(requested, cursor, fallback) { + if (requested !== void 0 && requested !== "ascending" && requested !== "descending") { + throw new StorageRequestError(`Invalid scan order: ${String(requested)}`); + } + if (cursor === void 0) + return { order: requested ?? fallback, after: void 0 }; + const { after, order: stored } = cursor; + if (typeof after !== "number" || !Number.isSafeInteger(after)) + throw new StorageRequestError("Invalid storage cursor"); + if (stored !== void 0 && stored !== "ascending" && stored !== "descending") { + throw new StorageRequestError("Invalid storage cursor"); + } + const order = stored ?? fallback; + if (requested !== void 0 && requested !== order) { + throw new StorageRequestError(`The cursor continues a ${order} scan; the query asks for ${requested}`); + } + return { order, after }; +} +function nextCursor(id, order) { + return { after: id, order }; +} + +// node_modules/@earendil-works/chord/dist/sqlite/schema.js +function validateSqliteSchemaPrefix(prefix) { + if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(prefix)) { + throw new Error(`Invalid SQLite schema prefix ${JSON.stringify(prefix)}`); + } + if (prefix.toLowerCase().startsWith("sqlite_")) { + throw new Error(`SQLite schema prefix ${JSON.stringify(prefix)} is reserved`); + } +} + +// node_modules/@earendil-works/chord/dist/sqlite/migrations.js +async function applySqliteMigrations(database, migrations, options) { + const { table } = options; + validateSqliteSchemaPrefix(table); + for (let index = 0; index < migrations.length; index++) { + if (migrations[index]?.version !== index + 1) { + throw new Error("SQLite migrations must have contiguous versions starting at 1"); + } + } + await database.transaction(async (transaction) => { + await transaction.exec(`CREATE TABLE IF NOT EXISTS ${table} ( + singleton INTEGER PRIMARY KEY CHECK (singleton = 1), + version INTEGER NOT NULL CHECK (version >= 0) + ) STRICT`); + await transaction.run(`INSERT OR IGNORE INTO ${table} (singleton, version) VALUES (1, 0)`); + const row = await transaction.get(`SELECT version FROM ${table} WHERE singleton = 1`); + if (row === void 0) + throw new Error("SQLite schema metadata is missing"); + const currentVersion = migrations.at(-1)?.version ?? 0; + if (row.version > currentVersion) { + throw new Error(`SQLite schema version ${row.version} is newer than supported version ${currentVersion}`); + } + for (const migration of migrations) { + if (migration.version <= row.version) + continue; + for (const statement of migration.statements) + await transaction.exec(statement); + await transaction.run(`UPDATE ${table} SET version = ? WHERE singleton = 1`, migration.version); + } + }); +} + +// node_modules/@earendil-works/pi-durable/dist/storage/sqlite/schema.js +var TABLE_NAMES = { + durableSchema: "durable_schema", + durableMetadata: "durable_metadata", + recordIds: "record_ids", + conversations: "conversations", + entries: "entries", + tasks: "tasks", + submissions: "submissions", + documents: "documents", + documentRevisions: "document_revisions" +}; +var INDEX_NAMES = { + conversationsByOwnerConversation: "conversations_by_owner_conversation", + conversationsByOwnerTask: "conversations_by_owner_task", + entriesByConversation: "entries_by_conversation", + entryHeadsByConversation: "entry_heads_by_conversation", + tasksByStatus: "tasks_by_status", + tasksByConversation: "tasks_by_conversation", + tasksByKind: "tasks_by_kind", + tasksByAbortRequested: "tasks_by_abort_requested", + tasksByBackground: "tasks_by_background", + submissionsByRequest: "submissions_by_request", + submissionsByConversation: "submissions_by_conversation", + submissionsByStatus: "submissions_by_status", + documentsByAddress: "documents_by_address", + documentsByScope: "documents_by_scope", + documentsByScopeKind: "documents_by_scope_kind", + documentRevisionsByKind: "document_revisions_by_kind" +}; +function prefixIdentifiers(names2, prefix) { + return Object.fromEntries(Object.entries(names2).map(([key, name]) => [key, `${prefix}${name}`])); +} +function createSqliteSchema(prefix) { + if (prefix !== void 0) + validateSqliteSchemaPrefix(prefix); + const actualPrefix = prefix ?? ""; + return { + tables: prefixIdentifiers(TABLE_NAMES, actualPrefix), + indexes: prefixIdentifiers(INDEX_NAMES, actualPrefix) + }; +} +var DEFAULT_SQLITE_SCHEMA = createSqliteSchema(); + +// node_modules/@earendil-works/pi-durable/dist/storage/sqlite/migrations.js +function createSqliteMigrations(schema) { + const { tables, indexes } = schema; + const initialSchema = [ + `CREATE TABLE ${tables.durableMetadata} ( + singleton INTEGER PRIMARY KEY CHECK (singleton = 1), + next_id TEXT NOT NULL, + next_seq INTEGER NOT NULL + ) STRICT`, + `INSERT INTO ${tables.durableMetadata} (singleton, next_id, next_seq) VALUES (1, '2', 1)`, + `CREATE TABLE ${tables.recordIds} ( + id INTEGER PRIMARY KEY, + record_type TEXT NOT NULL CHECK (record_type IN ('conversation', 'entry', 'task', 'submission', 'document')) + ) STRICT`, + `CREATE TABLE ${tables.conversations} ( + id INTEGER PRIMARY KEY, + owner_conversation_id INTEGER, + owner_task_id INTEGER, + record TEXT NOT NULL CHECK (json_valid(record)) + ) STRICT`, + `CREATE INDEX ${indexes.conversationsByOwnerConversation} ON ${tables.conversations} (owner_conversation_id, id)`, + `CREATE INDEX ${indexes.conversationsByOwnerTask} ON ${tables.conversations} (owner_task_id, id)`, + `CREATE TABLE ${tables.entries} ( + id INTEGER PRIMARY KEY, + conversation_id INTEGER NOT NULL, + head INTEGER, + commit_seq INTEGER NOT NULL, + record TEXT NOT NULL CHECK (json_valid(record)) + ) STRICT`, + `CREATE INDEX ${indexes.entriesByConversation} ON ${tables.entries} (conversation_id, id DESC)`, + `CREATE INDEX ${indexes.entryHeadsByConversation} ON ${tables.entries} (conversation_id, id DESC) WHERE head IS NOT NULL`, + `CREATE TABLE ${tables.tasks} ( + id INTEGER PRIMARY KEY, + conversation_id INTEGER NOT NULL, + kind TEXT NOT NULL, + status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'waiting', 'completing', 'terminal')), + abort_requested INTEGER NOT NULL CHECK (abort_requested IN (0, 1)), + background INTEGER NOT NULL CHECK (background IN (0, 1)), + record TEXT NOT NULL CHECK (json_valid(record)) + ) STRICT`, + `CREATE INDEX ${indexes.tasksByStatus} ON ${tables.tasks} (status, id)`, + `CREATE INDEX ${indexes.tasksByConversation} ON ${tables.tasks} (conversation_id, id)`, + `CREATE INDEX ${indexes.tasksByKind} ON ${tables.tasks} (kind, id)`, + `CREATE INDEX ${indexes.tasksByAbortRequested} ON ${tables.tasks} (abort_requested, id)`, + `CREATE INDEX ${indexes.tasksByBackground} ON ${tables.tasks} (background, id)`, + `CREATE TABLE ${tables.submissions} ( + id INTEGER PRIMARY KEY, + conversation_id INTEGER NOT NULL, + request_id TEXT, + status TEXT NOT NULL CHECK (status IN ('queued', 'placed', 'done', 'unanswered')), + record TEXT NOT NULL CHECK (json_valid(record)) + ) STRICT`, + `CREATE INDEX ${indexes.submissionsByRequest} ON ${tables.submissions} (conversation_id, request_id)`, + `CREATE INDEX ${indexes.submissionsByConversation} ON ${tables.submissions} (conversation_id, id)`, + `CREATE INDEX ${indexes.submissionsByStatus} ON ${tables.submissions} (status, id)`, + `CREATE TABLE ${tables.documents} ( + id INTEGER PRIMARY KEY, + kind TEXT NOT NULL, + family INTEGER NOT NULL CHECK (family IN (0, 1)), + key_value TEXT NOT NULL, + scope_kind TEXT NOT NULL CHECK (scope_kind IN ('session', 'conversation', 'task')), + owner_id INTEGER NOT NULL, + created_at INTEGER NOT NULL, + retired_at INTEGER, + record TEXT NOT NULL CHECK (json_valid(record)) + ) STRICT`, + `CREATE INDEX ${indexes.documentsByAddress} + ON ${tables.documents} (kind, scope_kind, owner_id, family, key_value, created_at DESC, retired_at)`, + `CREATE INDEX ${indexes.documentsByScope} ON ${tables.documents} (scope_kind, owner_id, id)`, + `CREATE INDEX ${indexes.documentsByScopeKind} ON ${tables.documents} (scope_kind, owner_id, kind, id)`, + `CREATE TABLE ${tables.documentRevisions} ( + document_id INTEGER NOT NULL, + seq INTEGER NOT NULL, + kind TEXT NOT NULL CHECK (kind IN ('base', 'delta')), + version INTEGER NOT NULL, + content TEXT NOT NULL CHECK (json_valid(content)), + PRIMARY KEY (document_id, seq) + ) STRICT`, + `CREATE INDEX ${indexes.documentRevisionsByKind} ON ${tables.documentRevisions} (document_id, kind, seq DESC)` + ]; + const rebuiltTasks = `${tables.tasks}_v2`; + const sleepingStatus = [ + `CREATE TABLE ${rebuiltTasks} ( + id INTEGER PRIMARY KEY, + conversation_id INTEGER NOT NULL, + kind TEXT NOT NULL, + status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'waiting', 'sleeping', 'completing', 'terminal')), + abort_requested INTEGER NOT NULL CHECK (abort_requested IN (0, 1)), + background INTEGER NOT NULL CHECK (background IN (0, 1)), + record TEXT NOT NULL CHECK (json_valid(record)) + ) STRICT`, + `INSERT INTO ${rebuiltTasks} (id, conversation_id, kind, status, abort_requested, background, record) + SELECT id, conversation_id, kind, status, abort_requested, background, record FROM ${tables.tasks}`, + `DROP TABLE ${tables.tasks}`, + `ALTER TABLE ${rebuiltTasks} RENAME TO ${tables.tasks}`, + `CREATE INDEX ${indexes.tasksByStatus} ON ${tables.tasks} (status, id)`, + `CREATE INDEX ${indexes.tasksByConversation} ON ${tables.tasks} (conversation_id, id)`, + `CREATE INDEX ${indexes.tasksByKind} ON ${tables.tasks} (kind, id)`, + `CREATE INDEX ${indexes.tasksByAbortRequested} ON ${tables.tasks} (abort_requested, id)`, + `CREATE INDEX ${indexes.tasksByBackground} ON ${tables.tasks} (background, id)` + ]; + return [ + { version: 1, statements: initialSchema }, + { version: 2, statements: sleepingStatus } + ]; +} +var SQLITE_MIGRATIONS = createSqliteMigrations(DEFAULT_SQLITE_SCHEMA); +var CURRENT_SQLITE_SCHEMA_VERSION = SQLITE_MIGRATIONS.at(-1)?.version ?? 0; +async function applySqliteMigrationsForSchema(database, schema, migrations = createSqliteMigrations(schema)) { + await applySqliteMigrations(database, migrations, { table: schema.tables.durableSchema }); +} + +// node_modules/@earendil-works/pi-durable/dist/storage/sqlite/storage.js +var parseJson = (value2) => JSON.parse(value2); +var encodeJson = (value2) => JSON.stringify(value2); +var encodeIndexedString = (value2) => JSON.stringify(value2); +var cursorId = (cursor) => { + const after = cursor?.after; + if (after === void 0) + return void 0; + if (typeof after !== "number" || !Number.isSafeInteger(after)) + throw new StorageRequestError("Invalid storage cursor"); + return idFromNumber(after); +}; +var page = (values, limit, order = "ascending") => { + const items = values.slice(0, limit); + if (values.length <= limit) + return { items }; + return { items, next: nextCursor(items.at(-1).id, order) }; +}; +var scanSql = (start) => start.order === "ascending" ? { clause: "id > ?", param: start.after ?? -1, direction: "ASC" } : { clause: "id < ?", param: start.after ?? Number.MAX_SAFE_INTEGER, direction: "DESC" }; +var scopeColumns = (scope) => { + switch (scope.kind) { + case "session": + return { scopeKind: "session", ownerId: 0 }; + case "conversation": + return { scopeKind: "conversation", ownerId: scope.conversationId }; + case "task": + return { scopeKind: "task", ownerId: scope.taskId }; + } +}; +var addressParts = (address) => { + const scope = scopeColumns(address.scope); + return { + kind: encodeIndexedString(address.kind), + ...scope, + family: address.key === void 0 ? 0 : 1, + keyValue: encodeIndexedString(address.key ?? "") + }; +}; +var addressKey = (address) => { + const parts = addressParts(address); + return JSON.stringify([parts.kind, parts.scopeKind, parts.ownerId, parts.family, parts.keyValue]); +}; +var isAliveAt = (record, at) => { + if (at === "current") + return record.retiredAt === void 0; + return record.createdAt <= at && (record.retiredAt === void 0 || at < record.retiredAt); +}; +var isCurrentOnly = (record) => record.scope.kind !== "conversation" || record.history === "latest"; +var writeId = (write) => { + switch (write.type) { + case "conversation": + case "entry": + case "task": + case "submission": + return write.value.id; + case "document.create": + case "document.copy": + return write.record.id; + case "document.change": + case "document.retire": + return void 0; + } +}; +function watchCalls(executor, calls) { + const watched = async (call) => { + try { + return await call(); + } catch (error) { + calls.failed = true; + throw error; + } + }; + return { + exec: (sql) => watched(() => executor.exec(sql)), + run: (sql, ...params) => watched(() => executor.run(sql, ...params)), + runCounted: (sql, ...params) => watched(() => executor.runCounted(sql, ...params)), + get: (sql, ...params) => watched(() => executor.get(sql, ...params)), + all: (sql, ...params) => watched(() => executor.all(sql, ...params)) + }; +} +var SqliteStorage = class _SqliteStorage { + db; + schema; + nextId; + closed = false; + closing; + admittedReads = 0; + readsDrained; + constructor(db, schema, nextId) { + this.db = db; + this.schema = schema; + this.nextId = nextId; + } + /** Initialize storage over an owned SQLite database facade. */ + static async open(db, options = {}) { + try { + const schema = createSqliteSchema(options.prefix); + await applySqliteMigrationsForSchema(db, schema); + const metadata = await db.get(`SELECT next_id, next_seq FROM ${schema.tables.durableMetadata} WHERE singleton = 1`); + if (metadata === void 0) + throw new Error("Durable SQLite metadata is missing"); + return new _SqliteStorage(db, schema, Number(metadata.next_id)); + } catch (error) { + try { + await db.close(); + } catch { + } + throw error; + } + } + /** + * Commit `batches` in one SQL transaction, each with its own seq. Each batch is checked before it writes anything, + * against the state the earlier ones left, and the first one refused ends the batch: the transaction commits the ones + * before it. No savepoints, which Durable Objects do not allow: the checks run before the writes instead. + */ + async commit(batches, receive, _context) { + this.assertOpen(); + const seqs = []; + let refused; + let candidateNextId = this.nextId; + await this.db.transaction(async (transaction) => { + const metadata = await this.readMetadata(transaction); + let next = metadata.next_seq; + const calls = { failed: false }; + const checked = watchCalls(transaction, calls); + for (const writes of batches) { + let documentActions; + calls.failed = false; + try { + documentActions = this.prepareDocumentActions(writes); + await this.checkBatch(checked, writes, documentActions); + } catch (error) { + if (calls.failed) + throw error; + refused = { error }; + break; + } + const seq = seqFromNumber(next++); + await this.applyBatch(transaction, writes, documentActions, seq); + seqs.push(seq); + candidateNextId = Math.max(candidateNextId, this.candidateNextId(writes)); + } + if (seqs.length > 0) { + await this.writeMetadata(transaction, Math.max(Number(metadata.next_id), candidateNextId), next); + } + }); + this.nextId = Math.max(this.nextId, candidateNextId); + for (const [index, seq] of seqs.entries()) + receive(index, seq); + return refused === void 0 ? { stored: seqs.length } : { stored: seqs.length, refused: refused.error }; + } + async readMetadata(executor) { + const metadata = await executor.get(`SELECT next_id, next_seq FROM ${this.schema.tables.durableMetadata} WHERE singleton = 1`); + if (metadata === void 0) + throw new Error("Durable SQLite metadata is missing"); + return metadata; + } + async writeMetadata(executor, nextId, nextSeq) { + await executor.run(`UPDATE ${this.schema.tables.durableMetadata} SET next_id = ?, next_seq = ? WHERE singleton = 1`, String(nextId), nextSeq); + } + /** Durable's own checks of one batch, copy resolution included, before it writes anything. */ + async checkBatch(executor, writes, documentActions) { + await this.checkGlobalIds(executor, writes); + await this.checkDocumentActions(executor, documentActions); + await this.resolveCopies(executor, documentActions); + } + async applyBatch(executor, writes, documentActions, seq) { + for (const write of writes) + await this.applyTableWrite(executor, write, seq); + await this.applyDocumentActions(executor, documentActions, seq); + } + async mintId() { + this.assertOpen(); + if (!Number.isSafeInteger(this.nextId)) + throw new Error("ID space is exhausted"); + return idFromNumber(this.nextId++); + } + async conversation(id, _context) { + this.assertOpen(); + const row = await this.db.get(`SELECT record FROM ${this.schema.tables.conversations} WHERE id = ?`, id); + return row === void 0 ? void 0 : parseJson(row.record); + } + async scanConversations(query, limit, cursor, _context) { + this.assertOpen(); + const start = scanStart(query.order, cursor, "ascending"); + const scan = scanSql(start); + const clauses = [scan.clause]; + const params = [scan.param]; + if (query.ownerConversationId !== void 0) { + clauses.push("owner_conversation_id = ?"); + params.push(query.ownerConversationId); + } + if (query.ownerTaskId !== void 0) { + clauses.push("owner_task_id = ?"); + params.push(query.ownerTaskId); + } + params.push(limit + 1); + const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.conversations} WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params); + return page(rows.map((row) => parseJson(row.record)), limit, start.order); + } + entry(idOrConversationId, idOrContext, context) { + return this.admitRead(() => this.readEntry(idOrConversationId, idOrContext, context)); + } + findLatestHeadMarker(conversationId, atOrBeforeEntryId, _context) { + return this.admitRead(() => this.readLatestHeadMarker(conversationId, atOrBeforeEntryId)); + } + scanEntries(query, limit, cursor, _context) { + return this.admitRead(() => this.readEntries(query, limit, cursor)); + } + async readEntry(idOrConversationId, idOrContext, context) { + const id = context === void 0 ? idFromNumber(idOrConversationId) : typeof idOrContext === "number" ? idFromNumber(idOrContext) : void 0; + if (id === void 0) + throw new StorageRequestError("Storage.entry() requires an entry ID"); + let conversation; + if (context !== void 0) { + const conversationId = idFromNumber(idOrConversationId); + conversation = await this.readConversation(conversationId); + if (conversation === void 0) + throw new StorageRequestError(`Unknown conversation: ${conversationId}`); + } + const row = await this.db.get(`SELECT record, commit_seq FROM ${this.schema.tables.entries} WHERE id = ?`, id); + if (row === void 0) + return void 0; + const entry2 = parseJson(row.record); + if (conversation !== void 0) { + let upperEntryId = Number.POSITIVE_INFINITY; + while (conversation.id !== entry2.conversationId) { + if (conversation.parent === void 0) + return void 0; + upperEntryId = Math.min(upperEntryId, conversation.parent.at); + conversation = await this.readConversation(conversation.parent.conversationId); + } + if (entry2.id > upperEntryId) + return void 0; + } + return { entry: entry2, commitSeq: seqFromNumber(row.commit_seq) }; + } + async readLatestHeadMarker(conversationId, atOrBeforeEntryId) { + let conversation = await this.readConversation(conversationId); + if (conversation === void 0) + throw new StorageRequestError(`Unknown conversation: ${conversationId}`); + let upper = atOrBeforeEntryId; + while (true) { + const row = upper === void 0 ? await this.db.get(`SELECT record FROM ${this.schema.tables.entries} WHERE conversation_id = ? AND head IS NOT NULL ORDER BY id DESC LIMIT 1`, conversation.id) : await this.db.get(`SELECT record FROM ${this.schema.tables.entries} WHERE conversation_id = ? AND head IS NOT NULL AND id <= ? ORDER BY id DESC LIMIT 1`, conversation.id, upper); + if (row !== void 0) + return parseJson(row.record); + if (conversation.parent === void 0) + return void 0; + upper = upper === void 0 ? conversation.parent.at : Math.min(upper, conversation.parent.at); + conversation = await this.readConversation(conversation.parent.conversationId); + } + } + async readEntries(query, limit, cursor) { + const { order, after } = scanStart(query.order, cursor, "descending"); + if (order === "ascending") + return this.readEntriesAscending(query, limit, after); + let conversation = await this.readConversation(query.conversationId); + if (conversation === void 0) + throw new StorageRequestError(`Unknown conversation: ${query.conversationId}`); + let upper = query.maxEntryId; + if (after !== void 0) + upper = Math.min(upper ?? Number.MAX_SAFE_INTEGER, after - 1); + const values = []; + while (true) { + const clauses = ["conversation_id = ?"]; + const params = [conversation.id]; + if (query.minEntryId !== void 0) { + clauses.push("id >= ?"); + params.push(query.minEntryId); + } + if (upper !== void 0) { + clauses.push("id <= ?"); + params.push(upper); + } + params.push(limit + 1 - values.length); + const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.entries} WHERE ${clauses.join(" AND ")} ORDER BY id DESC LIMIT ?`, ...params); + values.push(...rows.map((row) => parseJson(row.record))); + if (values.length > limit || conversation.parent === void 0) + break; + upper = upper === void 0 ? conversation.parent.at : Math.min(upper, conversation.parent.at); + if (query.minEntryId !== void 0 && upper < query.minEntryId) + break; + conversation = await this.readConversation(conversation.parent.conversationId); + } + return page(values, limit, "descending"); + } + /** Oldest first: the fork chain's segments from the root conversation forward, each up to its fork point. */ + async readEntriesAscending(query, limit, after) { + const segments = []; + let conversation = await this.readConversation(query.conversationId); + if (conversation === void 0) + throw new StorageRequestError(`Unknown conversation: ${query.conversationId}`); + let upper = query.maxEntryId; + while (true) { + segments.push({ conversationId: conversation.id, upper }); + if (conversation.parent === void 0) + break; + upper = upper === void 0 ? conversation.parent.at : Math.min(upper, conversation.parent.at); + if (query.minEntryId !== void 0 && upper < query.minEntryId) + break; + conversation = await this.readConversation(conversation.parent.conversationId); + } + let lower = query.minEntryId; + if (after !== void 0) + lower = Math.max(lower ?? after + 1, after + 1); + const values = []; + for (const segment of segments.reverse()) { + const clauses = ["conversation_id = ?"]; + const params = [segment.conversationId]; + if (lower !== void 0) { + clauses.push("id >= ?"); + params.push(lower); + } + if (segment.upper !== void 0) { + clauses.push("id <= ?"); + params.push(segment.upper); + } + params.push(limit + 1 - values.length); + const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.entries} WHERE ${clauses.join(" AND ")} ORDER BY id ASC LIMIT ?`, ...params); + values.push(...rows.map((row) => parseJson(row.record))); + if (values.length > limit) + break; + } + return page(values, limit, "ascending"); + } + async task(id, _context) { + this.assertOpen(); + const row = await this.db.get(`SELECT record FROM ${this.schema.tables.tasks} WHERE id = ?`, id); + return row === void 0 ? void 0 : parseJson(row.record); + } + async scanTasks(query, limit, cursor, _context) { + this.assertOpen(); + const start = scanStart(query.order, cursor, "ascending"); + const scan = scanSql(start); + const clauses = [scan.clause]; + const params = [scan.param]; + if (query.conversationId !== void 0) { + clauses.push("conversation_id = ?"); + params.push(query.conversationId); + } + if (query.kind !== void 0) { + clauses.push("kind = ?"); + params.push(encodeIndexedString(query.kind)); + } + if (query.status !== void 0) { + clauses.push("status = ?"); + params.push(query.status); + } + if (query.abortRequested !== void 0) { + clauses.push("abort_requested = ?"); + params.push(query.abortRequested ? 1 : 0); + } + if (query.background !== void 0) { + clauses.push("background = ?"); + params.push(query.background ? 1 : 0); + } + params.push(limit + 1); + const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.tasks} WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params); + return page(rows.map((row) => parseJson(row.record)), limit, start.order); + } + async submission(id, _context) { + this.assertOpen(); + const row = await this.db.get(`SELECT record FROM ${this.schema.tables.submissions} WHERE id = ?`, id); + return row === void 0 ? void 0 : parseJson(row.record); + } + async scanSubmissions(query, limit, cursor, _context) { + this.assertOpen(); + const start = scanStart(query.order, cursor, "ascending"); + const scan = scanSql(start); + const clauses = [scan.clause]; + const params = [scan.param]; + if (query.conversationId !== void 0) { + clauses.push("conversation_id = ?"); + params.push(query.conversationId); + } + if (query.status !== void 0) { + clauses.push("status = ?"); + params.push(query.status); + } + params.push(limit + 1); + const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.submissions} WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params); + return page(rows.map((row) => parseJson(row.record)), limit, start.order); + } + async submissionByRequest(conversationId, requestId, _context) { + this.assertOpen(); + const row = await this.db.get(`SELECT record FROM ${this.schema.tables.submissions} WHERE conversation_id = ? AND request_id = ?`, conversationId, encodeIndexedString(requestId)); + return row === void 0 ? void 0 : parseJson(row.record); + } + async findDocument(address, at, _context) { + this.assertOpen(); + const parts = addressParts(address); + const sql = at === "current" ? `SELECT record FROM ${this.schema.tables.documents} + WHERE kind = ? AND scope_kind = ? AND owner_id = ? AND family = ? AND key_value = ? + AND retired_at IS NULL ORDER BY created_at DESC LIMIT 1` : `SELECT record FROM ${this.schema.tables.documents} + WHERE kind = ? AND scope_kind = ? AND owner_id = ? AND family = ? AND key_value = ? + AND created_at <= ? AND (retired_at IS NULL OR retired_at > ?) + ORDER BY created_at DESC LIMIT 1`; + const params = [parts.kind, parts.scopeKind, parts.ownerId, parts.family, parts.keyValue]; + if (at !== "current") + params.push(at, at); + const row = await this.db.get(sql, ...params); + return row === void 0 ? void 0 : parseJson(row.record); + } + async document(id, at, _context) { + this.assertOpen(); + return this.db.transaction((transaction) => this.materializeDocument(transaction, id, at)); + } + async scanDocuments(query, limit, cursor, _context) { + this.assertOpen(); + const scope = scopeColumns(query.scope); + const clauses = ["scope_kind = ?", "owner_id = ?", "id > ?"]; + const params = [scope.scopeKind, scope.ownerId, cursorId(cursor) ?? -1]; + if (query.kind !== void 0) { + clauses.push("kind = ?"); + params.push(encodeIndexedString(query.kind)); + } + if (query.at === "current") { + clauses.push("retired_at IS NULL"); + } else { + clauses.push("created_at <= ?", "(retired_at IS NULL OR retired_at > ?)"); + params.push(query.at, query.at); + } + params.push(limit + 1); + const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.documents} WHERE ${clauses.join(" AND ")} ORDER BY id LIMIT ?`, ...params); + return page(rows.map((row) => parseJson(row.record)), limit); + } + close(_context) { + if (this.closing === void 0) { + this.closed = true; + this.closing = this.closeDatabase(); + } + return this.closing; + } + async closeDatabase() { + if (this.admittedReads > 0) { + await new Promise((resolve2) => { + this.readsDrained = resolve2; + }); + } + await this.db.close(); + } + /** + * Run a read that issues several queries. Close waits for admitted reads, so their later queries never reach a + * closed database. Single-query reads and transactions are already ordered before close by the database. + */ + async admitRead(read2) { + this.assertOpen(); + this.admittedReads++; + try { + return await read2(); + } finally { + if (--this.admittedReads === 0) + this.readsDrained?.(); + } + } + async readConversation(id) { + const row = await this.db.get(`SELECT record FROM ${this.schema.tables.conversations} WHERE id = ?`, id); + return row === void 0 ? void 0 : parseJson(row.record); + } + async materializeDocument(executor, id, at) { + const row = await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id); + if (row === void 0) + return void 0; + const record = parseJson(row.record); + if (at !== "current" && isCurrentOnly(record)) { + throw new StorageRequestError(`Document ${id} does not retain historical content`); + } + if (!isAliveAt(record, at)) + return void 0; + const upper = at === "current" ? Number.MAX_SAFE_INTEGER : at; + const base = await executor.get(`SELECT seq, kind, version, content FROM ${this.schema.tables.documentRevisions} + WHERE document_id = ? AND kind = 'base' AND seq <= ? ORDER BY seq DESC LIMIT 1`, id, upper); + if (base === void 0) + throw new Error(`Document ${id} is missing a required base`); + let value2 = parseJson(base.content); + const tail = await executor.all(`SELECT seq, kind, version, content FROM ${this.schema.tables.documentRevisions} + WHERE document_id = ? AND seq > ? AND seq <= ? ORDER BY seq`, id, base.seq, upper); + for (const revision of tail) { + if (revision.kind !== "delta" || revision.version !== base.version) { + throw new Error(`Document ${id} crosses a stored version boundary without a base`); + } + value2 = apply(value2, parseJson(revision.content)); + } + return { record, version: base.version, value: value2, deltasSinceBase: tail.length }; + } + candidateNextId(writes) { + let nextId = this.nextId; + for (const write of writes) { + const id = writeId(write); + if (id !== void 0) + nextId = Math.max(nextId, id + 1); + } + return nextId; + } + async checkGlobalIds(executor, writes) { + const claimed = /* @__PURE__ */ new Map(); + for (const write of writes) { + if (write.type === "document.change" || write.type === "document.retire") + continue; + const document = write.type === "document.create" || write.type === "document.copy"; + const table = document ? "document" : write.type; + const id = document ? write.record.id : write.value.id; + const existing = (await executor.get(`SELECT record_type FROM ${this.schema.tables.recordIds} WHERE id = ?`, id))?.record_type; + const earlier = claimed.get(id); + if (table === "conversation" || table === "entry" || table === "document") { + if (existing !== void 0) + throw new Error(`ID ${id} already belongs to ${existing}`); + if (earlier !== void 0) + throw new Error(`ID ${id} is written more than once`); + } else { + if (existing !== void 0 && existing !== table) + throw new Error(`ID ${id} already belongs to ${existing}`); + if (earlier !== void 0 && earlier !== table) + throw new Error(`ID ${id} is written as two record types`); + } + claimed.set(id, table); + } + } + prepareDocumentActions(writes) { + const actions = /* @__PURE__ */ new Map(); + for (const write of writes) { + if (write.type !== "document.create" && write.type !== "document.copy" && write.type !== "document.change" && write.type !== "document.retire") { + continue; + } + const id = write.type === "document.create" || write.type === "document.copy" ? write.record.id : write.id; + let action = actions.get(id); + if (action === void 0) { + action = { retire: false }; + actions.set(id, action); + } + switch (write.type) { + case "document.create": + if (action.create !== void 0 || action.content !== void 0 || action.copy !== void 0) { + throw new Error(`Document ${id} has more than one content command`); + } + action.create = write.record; + action.content = write.content; + break; + case "document.copy": + if (action.create !== void 0 || action.content !== void 0 || action.copy !== void 0) { + throw new Error(`Document ${id} has more than one content command`); + } + action.create = write.record; + action.copy = write.source; + break; + case "document.change": + if (action.content !== void 0 || action.copy !== void 0) { + throw new Error(`Document ${id} has more than one content command`); + } + action.content = write.content; + break; + case "document.retire": + if (action.retire) + throw new Error(`Document ${id} is retired more than once`); + action.retire = true; + break; + } + } + return actions; + } + async checkDocumentActions(executor, actions) { + const liveCounts = /* @__PURE__ */ new Map(); + for (const [id, action] of actions) { + if (action.copy !== void 0 && actions.has(action.copy.id)) { + throw new Error(`Document copy ${id} source is changed in the copy batch`); + } + const row = await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id); + const existing = row === void 0 ? void 0 : parseJson(row.record); + if (action.create === void 0 && existing === void 0) + throw new Error(`Unknown document: ${id}`); + if (action.create !== void 0 && existing !== void 0) + throw new Error(`Document ${id} already exists`); + if (existing?.retiredAt !== void 0) + throw new Error(`Document ${id} is retired`); + if (action.content?.kind === "delta") { + const previous = await executor.get(`SELECT version FROM ${this.schema.tables.documentRevisions} WHERE document_id = ? ORDER BY seq DESC LIMIT 1`, id); + if (previous === void 0) + throw new Error(`Document ${id} delta has no base`); + if (previous.version !== action.content.version) { + throw new Error(`Document ${id} version transition requires a base`); + } + } + const record = action.create ?? existing; + const key = addressKey(record); + let live = liveCounts.get(key); + if (live === void 0) + live = await this.currentDocumentId(executor, record) === void 0 ? 0 : 1; + if (action.retire && existing !== void 0) + live--; + if (action.create !== void 0 && !action.retire) + live++; + liveCounts.set(key, live); + } + for (const live of liveCounts.values()) { + if (live > 1) + throw new Error("Document address already has a current incarnation"); + } + } + async currentDocumentId(executor, address) { + const parts = addressParts(address); + const id = (await executor.get(`SELECT id FROM ${this.schema.tables.documents} + WHERE kind = ? AND scope_kind = ? AND owner_id = ? AND family = ? AND key_value = ? AND retired_at IS NULL + LIMIT 1`, parts.kind, parts.scopeKind, parts.ownerId, parts.family, parts.keyValue))?.id; + return id === void 0 ? void 0 : idFromNumber(id); + } + async applyTableWrite(executor, write, seq) { + switch (write.type) { + case "conversation": + await this.claimId(executor, write.value.id, "conversation"); + await executor.run(`INSERT INTO ${this.schema.tables.conversations} (id, owner_conversation_id, owner_task_id, record) VALUES (?, ?, ?, ?)`, write.value.id, write.value.owner?.conversationId ?? null, write.value.owner?.taskId ?? null, encodeJson(write.value)); + break; + case "entry": + await this.claimId(executor, write.value.id, "entry"); + await executor.run(`INSERT INTO ${this.schema.tables.entries} (id, conversation_id, head, commit_seq, record) VALUES (?, ?, ?, ?, ?)`, write.value.id, write.value.conversationId, write.value.head ?? null, seq, encodeJson(write.value)); + break; + case "task": + await this.claimId(executor, write.value.id, "task"); + await executor.run(`INSERT INTO ${this.schema.tables.tasks} (id, conversation_id, kind, status, abort_requested, background, record) + VALUES (?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(id) DO UPDATE SET conversation_id = excluded.conversation_id, kind = excluded.kind, + status = excluded.status, abort_requested = excluded.abort_requested, + background = excluded.background, record = excluded.record`, write.value.id, write.value.conversationId, encodeIndexedString(write.value.kind), write.value.state.status, write.value.abortRequested ? 1 : 0, write.value.background ? 1 : 0, encodeJson(write.value)); + break; + case "submission": + await this.claimId(executor, write.value.id, "submission"); + await executor.run(`INSERT INTO ${this.schema.tables.submissions} (id, conversation_id, request_id, status, record) VALUES (?, ?, ?, ?, ?) + ON CONFLICT(id) DO UPDATE SET conversation_id = excluded.conversation_id, + request_id = excluded.request_id, status = excluded.status, record = excluded.record`, write.value.id, write.value.conversationId, write.value.requestId === void 0 ? null : encodeIndexedString(write.value.requestId), write.value.status, encodeJson(write.value)); + break; + case "document.create": + case "document.copy": + case "document.change": + case "document.retire": + break; + } + } + async claimId(executor, id, table) { + await executor.run(`INSERT OR IGNORE INTO ${this.schema.tables.recordIds} (id, record_type) VALUES (?, ?)`, id, table); + } + /** Resolve each copy to a base of its source's state before this batch, which may not change the source. */ + async resolveCopies(executor, actions) { + for (const [id, action] of actions) { + if (action.copy === void 0) + continue; + try { + const stored = await this.materializeDocument(executor, action.copy.id, action.copy.at); + if (stored === void 0) + throw new Error(`Fork source document ${action.copy.id} cannot be read`); + const create = action.create; + if (stored.record.scope.kind !== "conversation" || create.scope.kind !== "conversation" || stored.record.kind !== create.kind || stored.record.key !== create.key || stored.record.history !== create.history || stored.record.fork !== create.fork) { + throw new Error(`Fork source document ${action.copy.id} does not match the copied record`); + } + action.content = { kind: "base", version: stored.version, value: stored.value }; + } catch (error) { + throw new Error(`Document copy ${id} was rejected`, { cause: error }); + } + } + } + async applyDocumentActions(executor, actions, seq) { + for (const [id, action] of actions) { + const content = action.content; + let record; + if (action.create !== void 0) { + record = { + ...action.create, + createdAt: seq, + ...action.retire ? { retiredAt: seq } : {} + }; + const parts = addressParts(record); + await this.claimId(executor, id, "document"); + await executor.run(`INSERT INTO ${this.schema.tables.documents} + (id, kind, family, key_value, scope_kind, owner_id, created_at, retired_at, record) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, id, parts.kind, parts.family, parts.keyValue, parts.scopeKind, parts.ownerId, seq, action.retire ? seq : null, encodeJson(record)); + } else { + const row = await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id); + record = parseJson(row.record); + } + if (content !== void 0) { + if (content.kind === "base" && isCurrentOnly(record)) { + await executor.run(`DELETE FROM ${this.schema.tables.documentRevisions} WHERE document_id = ?`, id); + } + const encodedContent = content.kind === "base" ? encodeJson(content.value) : encodeJson(content.ops); + await executor.run(`INSERT INTO ${this.schema.tables.documentRevisions} (document_id, seq, kind, version, content) VALUES (?, ?, ?, ?, ?)`, id, seq, content.kind, content.version, encodedContent); + } + if (action.retire) { + if (action.create === void 0) { + record = { ...record, retiredAt: seq }; + await executor.run(`UPDATE ${this.schema.tables.documents} SET retired_at = ?, record = ? WHERE id = ?`, seq, encodeJson(record), id); + } + if (isCurrentOnly(record)) { + await executor.run(`DELETE FROM ${this.schema.tables.documentRevisions} WHERE document_id = ?`, id); + } + } + } + } + assertOpen() { + if (this.closed) + throw new Error("SqliteStorage is closed"); + } +}; + +// sqlite.ts +var op = (kind, sql = "", params = []) => Deno.core.ops.op_sql(kind, sql, params.map((p) => p instanceof Uint8Array ? Array.from(p) : typeof p === "bigint" ? Number(p) : p)); +async function openStorage(path) { + op("open", path); + let tail = Promise.resolve(); + const queue = (call) => { + const result = tail.then(call); + tail = result.then(() => { + }, () => { + }); + return result; + }; + const executor = { + exec: async (sql) => { + op("exec", sql); + }, + run: async (sql, ...params) => { + op("run", sql, params); + }, + runCounted: async (sql, ...params) => op("run", sql, params).changes, + get: async (sql, ...params) => (await executor.all(sql, ...params))[0], + all: async (sql, ...params) => op("all", sql, params).map((row) => Object.fromEntries(Object.entries(row).map(([key, value2]) => [key, Array.isArray(value2) ? new Uint8Array(value2) : value2]))) + }; + const database = Object.fromEntries(Object.entries(executor).map(([name, method]) => [name, (...args) => queue(() => method(...args))])); + database.transaction = (callback) => queue(async () => { + op("exec", "BEGIN IMMEDIATE"); + try { + const result = await callback(executor); + op("exec", "COMMIT"); + return result; + } catch (error) { + op("exec", "ROLLBACK"); + throw error; + } + }); + database.close = () => queue(async () => { + op("close"); + }); + return SqliteStorage.open(database); +} + +// credentials.ts +var Requests = defineDoc({ + kind: "sausage.credential.requests", + version: 1, + scope: "conversation", + history: "latest", + fork: "initial", + initial: () => ({ ids: [] }), + checkpointWhen: () => false +}); +var Wait = defineTask({ + name: "sausage.credential.wait", + version: 1, + initial: () => ({ phase: "wait" }), + phases: { + wait: async (task, runtime, context) => { + const request2 = Deno.core.ops.op_credential_requests().find((r) => r.id === task.input.id); + if (!request2 || request2.state === "pending") { + await runtime.sleepUntil(Date.now() + 1e3, { phase: "wait" }, context); + return; + } + const conversation = await runtime.conversation(runtime.conversationId, context); + await runtime.commit(async (tx) => { + await conversation.submit(tx, { type: "input", content: request2.message, requestId: `credential:${request2.id}` }); + return { status: "terminal", outcome: { status: "completed", result: null } }; + }, context); + } + }, + abort: (_task, runtime, context) => runtime.commit(() => ({ status: "terminal", outcome: { status: "aborted" } }), context) +}); +var CredentialRequests = defineExtension({ name: "sausage.credentials", tasks: [Wait] }); +async function discoverRequests(harness2, context) { + for (const request2 of Deno.core.ops.op_credential_requests()) { + const conversation = await harness2.conversation(Number(request2.conversation), context); + if (!conversation) continue; + await conversation.commit(async (tx) => { + const recorded = await tx.doc(Requests, conversation.id); + if (recorded.ids.includes(request2.id)) return; + await tx.createTask(Wait, { id: request2.id }, { ownership: { kind: "conversation" }, background: true }); + recorded.ids.push(request2.id); + }, context); + } +} +async function startRequests(harness2, context) { + await discoverRequests(harness2, context); + let active = true; + const pending = (async () => { + while (active) { + await Deno.core.ops.op_credential_next(); + if (active) await discoverRequests(harness2, context); + } + })(); + return async () => { + active = false; + await pending; + }; +} + +// durable-test.ts +var models = createModels(); +var faux = fauxProvider({ tokensPerSecond: 1e5 }); +models.setProvider(faux.provider); +faux.setResponses(Array.from({ length: 8 }, () => fauxAssistantMessage([fauxText("done")]))); +var registry = createRegistry(); +registry.install(CredentialRequests); +var harness = await Harness.open(await openStorage(globalThis.storagePath), { models, registry }, BACKGROUND_CONTEXT); +var root = await harness.root(BACKGROUND_CONTEXT, { agent: { model: { provider: "faux", modelId: "faux-1" }, extensions: [CredentialRequests] } }); +await (await root.submit({ type: "input", content: "initial", requestId: "initial" }, BACKGROUND_CONTEXT)).wait(BACKGROUND_CONTEXT); +if (globalThis.proxyOnly) { + await harness.close(BACKGROUND_CONTEXT); +} else { + await Deno.core.ops.op_file("write", "/conversation", Array.from(new TextEncoder().encode(root.id))); + const stop2 = await startRequests(harness, BACKGROUND_CONTEXT); + harness.resume(); + const watch = await root.watch(BACKGROUND_CONTEXT); + await new Promise((resolve2, reject2) => { + const check = (event) => { + if (event.kind !== "value") return; + const messages = event.value.entries.filter((e) => JSON.stringify(e).includes("Your request for")); + if (messages.length > 1) reject2(new Error("Duplicate credential message")); + if (messages.length === 1) { + const message = JSON.stringify(messages); + if (!message.includes("`github`") || !message.includes(globalThis.expectedState)) reject2(new Error("Wrong credential decision message")); + else resolve2(); + } + }; + watch.start(check); + check({ kind: "value", value: watch.value }); + }); + await harness.waitForIdle(BACKGROUND_CONTEXT); + const final = await root.watch(BACKGROUND_CONTEXT); + if (final.value.entries.filter((entry2) => entry2.kind === "pi.assistant").length !== 2) { + throw new Error("The decision must start exactly one model turn"); + } + await final.stop(); + await stop2(); + await watch.stop(); + await harness.close(BACKGROUND_CONTEXT); +} diff --git a/host/js/durable-test.ts b/host/js/durable-test.ts new file mode 100644 index 0000000..6dc82bd --- /dev/null +++ b/host/js/durable-test.ts @@ -0,0 +1,47 @@ +// Faux-model acceptance probe for credential wake-ups, including host restart. +import { BACKGROUND_CONTEXT as context } from '@earendil-works/chord/context'; +import { createModels } from '@earendil-works/pi-ai/models'; +import { fauxProvider, fauxAssistantMessage, fauxText } from '@earendil-works/pi-ai/providers/faux'; +import { Harness, createRegistry } from '@earendil-works/pi-durable'; +import { openStorage } from './sqlite'; +import { CredentialRequests, startRequests } from './credentials'; +const models = createModels(); +const faux = fauxProvider({ tokensPerSecond: 100000 }); +models.setProvider(faux.provider); +faux.setResponses(Array.from({ length: 8 }, () => fauxAssistantMessage([fauxText('done')]))); +const registry = createRegistry(); +registry.install(CredentialRequests); +const harness = await Harness.open(await openStorage(globalThis.storagePath), { models, registry }, context); +const root = await harness.root(context, { agent: { model: { provider: 'faux', modelId: 'faux-1' }, extensions: [CredentialRequests] } }); +await (await root.submit({ type: 'input', content: 'initial', requestId: 'initial' }, context)).wait(context); +if (globalThis.proxyOnly) { + await harness.close(context); +} else { + await Deno.core.ops.op_file('write', '/conversation', Array.from(new TextEncoder().encode(root.id))); + const stop = await startRequests(harness, context); + harness.resume(); + const watch = await root.watch(context); + await new Promise((resolve, reject) => { + const check = (event: any) => { + if (event.kind !== 'value') return; + const messages = event.value.entries.filter((e: any) => JSON.stringify(e).includes('Your request for')); + if (messages.length > 1) reject(new Error('Duplicate credential message')); + if (messages.length === 1) { + const message = JSON.stringify(messages); + if (!message.includes('`github`') || !message.includes(globalThis.expectedState)) reject(new Error('Wrong credential decision message')); + else resolve(); + } + }; + watch.start(check); + check({ kind: 'value', value: watch.value }); + }); + await harness.waitForIdle(context); + const final = await root.watch(context); + if (final.value.entries.filter((entry: any) => entry.kind === 'pi.assistant').length !== 2) { + throw new Error('The decision must start exactly one model turn'); + } + await final.stop(); + await stop(); + await watch.stop(); + await harness.close(context); +} diff --git a/host/js/main.ts b/host/js/main.ts index ddb7fa9..f29bb0f 100644 --- a/host/js/main.ts +++ b/host/js/main.ts @@ -6,30 +6,31 @@ import { Harness, createRegistry } from '@earendil-works/pi-durable'; import { CodingTools } from '@earendil-works/pi-durable/tools'; import { openStorage } from './sqlite'; import { environment } from './environment'; -if (!process.env.PI_PROXY_BASE_URL || !process.env.PI_PROXY_API_KEY) { - throw new Error('PI_PROXY_BASE_URL and PI_PROXY_API_KEY are required'); -} +import { CredentialRequests, startRequests } from './credentials'; +const proxy = Deno.core.ops.op_model_proxy(); +if (!proxy?.base_url || !proxy?.api_key) throw new Error('The llm-proxy credential is required'); const models = createModels(); const provider = openaiProvider(); const model = { id: 'gpt-6.1-sol', name: 'gpt-6.1-sol', provider: 'openai', api: 'openai-responses', - baseUrl: `${process.env.PI_PROXY_BASE_URL}/v1`, reasoning: true, input: ['text'], + baseUrl: `${proxy.base_url}/v1`, reasoning: true, input: ['text'], thinkingLevelMap: { off: null, minimal: null }, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 200000, maxTokens: 4096, }; models.setProvider({ ...provider, baseUrl: model.baseUrl, getModels: () => [model], auth: { apiKey: { name: 'Sausage proxy', resolve: async () => ({ - auth: { apiKey: process.env.PI_PROXY_API_KEY, baseUrl: model.baseUrl, + auth: { apiKey: proxy.api_key, baseUrl: model.baseUrl, headers: { 'Shopify-Usage-Tag': JSON.stringify(['pi', 'sausage']) } }, - source: 'PI_PROXY_API_KEY', + source: 'llm-proxy', }) } }, }); const registry = createRegistry(); registry.install(CodingTools); +registry.install(CredentialRequests); const harness = await Harness.open(await openStorage(globalThis.storagePath), { models, registry, env: (target: any) => environment(target.cwd ?? '/', target.conversationId), }, context); -const root = await harness.root(context, { agent: { model: { provider: 'openai', modelId: model.id }, thinkingLevel: 'low', cwd: '/', extensions: [CodingTools] } }); +const root = await harness.root(context, { agent: { model: { provider: 'openai', modelId: model.id }, thinkingLevel: 'low', cwd: '/', extensions: [CodingTools, CredentialRequests] } }); const watch = await root.watch(context); const emitted = new Map(); let partial = ''; @@ -53,6 +54,7 @@ for (const entry of watch.value.entries) { if (entry.kind === 'pi.assistant') emitted.set(entry.id, text(entry.model?.[0])); } watch.start((event: any) => { if (event.kind === 'value') render(event.value); }); +const stopRequests = await startRequests(harness, context); harness.resume(); await harness.waitForIdle(context); while (true) { @@ -68,5 +70,6 @@ while (true) { Deno.core.ops.op_output('\n'); if (result.status !== 'done') throw new Error(`Run ended: ${JSON.stringify(result)}`); } +await stopRequests(); await watch.stop(); await harness.close(context); diff --git a/host/js/package.json b/host/js/package.json index 485ff4c..739fd6e 100644 --- a/host/js/package.json +++ b/host/js/package.json @@ -1,7 +1,7 @@ { "private": true, "type": "module", - "scripts": { "bundle": "esbuild main.ts --bundle --format=esm --platform=browser --outfile=bundle.js && esbuild test.ts --bundle --format=esm --platform=browser --outfile=test-bundle.js" }, + "scripts": { "bundle": "esbuild main.ts --bundle --format=esm --platform=browser --outfile=bundle.js && esbuild test.ts --bundle --format=esm --platform=browser --outfile=test-bundle.js && esbuild durable-test.ts --bundle --format=esm --platform=browser --outfile=durable-test-bundle.js" }, "dependencies": { "@earendil-works/pi-durable": "1.5.0", "@earendil-works/pi-ai": "1.5.0", diff --git a/host/src/cred/requests.rs b/host/src/cred/requests.rs index 7c207e6..90b0bef 100644 --- a/host/src/cred/requests.rs +++ b/host/src/cred/requests.rs @@ -182,6 +182,7 @@ impl Cred { if let Some(expired) = expired_id { let _ = self.decided.send(expired); } + let _ = self.filed.send(id.clone()); Ok(id) } pub fn request_list(&self) -> Result> { diff --git a/host/src/cred/store.rs b/host/src/cred/store.rs index fbebed3..48118b8 100644 --- a/host/src/cred/store.rs +++ b/host/src/cred/store.rs @@ -16,6 +16,7 @@ pub(crate) struct Store { pub struct Cred { pub(crate) store: Mutex, pub(crate) decided: tokio::sync::broadcast::Sender, + pub(crate) filed: tokio::sync::broadcast::Sender, } impl Cred { pub fn open(host_dir: &Path) -> Result { @@ -50,9 +51,11 @@ impl Cred { db.busy_timeout(std::time::Duration::from_secs(5))?; db.execute_batch(schema::DDL)?; let (decided, _) = tokio::sync::broadcast::channel(64); + let (filed, _) = tokio::sync::broadcast::channel(64); let cred = Self { store: Mutex::new(Store { db, master }), decided, + filed, }; cred.expire_requests()?; Ok(cred) @@ -60,6 +63,9 @@ impl Cred { pub(crate) fn access(&self) -> Result> { self.store.lock().map_err(|_| Error("storage")) } + pub fn subscribe_filed(&self) -> tokio::sync::broadcast::Receiver { + self.filed.subscribe() + } pub fn subscribe(&self) -> tokio::sync::broadcast::Receiver { self.decided.subscribe() } diff --git a/host/src/harness/credentials.rs b/host/src/harness/credentials.rs new file mode 100644 index 0000000..6799285 --- /dev/null +++ b/host/src/harness/credentials.rs @@ -0,0 +1,162 @@ +//! Credential request snapshots and host-only model proxy configuration. +use crate::cred::{store::Cred, types::Subject}; +use deno_core::{OpState, op2}; +use deno_error::JsErrorBox; +use serde_json::{Value, json}; +use std::{cell::RefCell, rc::Rc, sync::Arc}; + +pub(super) struct Notifications { + filed: tokio::sync::Mutex>, +} +impl Notifications { + pub(super) fn new(cred: &Cred) -> Rc { + Rc::new(Self { + filed: tokio::sync::Mutex::new(cred.subscribe_filed()), + }) + } +} +#[op2] +pub(super) async fn op_credential_next(state: Rc>) { + let notifications = state.borrow().borrow::>().clone(); + let mut filed = notifications.filed.lock().await; + let _ = tokio::time::timeout(std::time::Duration::from_secs(1), filed.recv()).await; +} + +#[op2] +#[serde] +pub(super) fn op_credential_requests(state: &mut OpState) -> Result { + let cred = state.borrow::>(); + let work = || -> anyhow::Result { + cred.expire_requests()?; + // TODO(T27): prune retained records once a day after the library adds Cred::prune. + let mut rows = Vec::new(); + for request in cred.request_list()? { + let Subject::Conversation(conversation) = request.subject else { + continue; + }; + let names = request + .payload + .get("items") + .and_then(Value::as_array) + .map(|items| { + items + .iter() + .filter_map(Value::as_str) + .map(|id| { + cred.item_get(id) + .map(|item| format!("`{}`", item.name)) + .unwrap_or_else(|_| "the credential".into()) + }) + .collect::>() + .join(", ") + }) + .unwrap_or_else(|| "the credential change".into()); + let message = match request.state.as_str() { + "approved" => format!("Your request for {names} was approved. Retry the command."), + "denied" => format!("Your request for {names} was denied."), + "expired" => format!( + "Your request for {names} expired. File a new request if you still need it." + ), + _ => String::new(), + }; + rows.push(json!({"id":request.id,"conversation":conversation,"state":request.state,"message":message})); + } + Ok(json!(rows)) + }; + work().map_err(|_| JsErrorBox::generic("Cannot read credential requests")) +} + +pub(super) fn proxy(cred: &Cred) -> anyhow::Result> { + use crate::cred::{ + items::{Field, Item}, + types::{Caller, FieldType}, + }; + let caller = Caller { + pid: 0, + program: "host".into(), + conversations: vec![], + }; + let item = cred + .item_list()? + .into_iter() + .find(|item| item.name == "llm-proxy"); + let item = match item { + Some(item) => item, + None => { + let (Ok(base), Ok(key)) = ( + std::env::var("PI_PROXY_BASE_URL"), + std::env::var("PI_PROXY_API_KEY"), + ) else { + return Ok(None); + }; + let mut store = cred.access()?; + let master = store.master.clone(); + let tx = store + .db + .transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; + let mut item = crate::cred::items::insert_new( + &tx, + Item { + id: String::new(), + name: "llm-proxy".into(), + version: 0, + free_use: false, + rules: vec![], + validate_js: None, + transform_js: "export default (ctx) => ctx.request".into(), + fields: vec![ + Field { + field_id: String::new(), + name: "base_url".into(), + public: true, + value: Some(base), + needs_value: false, + field_type: FieldType::Text, + key_type: None, + }, + Field { + field_id: String::new(), + name: "api_key".into(), + public: false, + value: None, + needs_value: true, + field_type: FieldType::Text, + key_type: None, + }, + ], + }, + &caller, + Some("host bootstrap"), + )?; + let field = &item + .fields + .iter() + .find(|f| f.name == "api_key") + .unwrap() + .field_id; + let sealed = + crate::cred::seal::seal(&master, &format!("{}|{field}", item.id), key.as_bytes())?; + tx.execute( + "INSERT INTO fields VALUES(?1,?2,?3)", + rusqlite::params![item.id, field, sealed], + )?; + item.fields + .iter_mut() + .find(|f| f.name == "api_key") + .unwrap() + .needs_value = false; + crate::cred::items::save(&tx, &item)?; + tx.commit()?; + item + } + }; + Ok(Some(cred.credential(&item, true)?)) +} + +#[op2] +#[serde] +pub(super) fn op_model_proxy(state: &mut OpState) -> Result { + proxy(state.borrow::>()) + .map(|v| v.unwrap_or(Value::Null)) + .map_err(|_| JsErrorBox::generic("Cannot read llm-proxy credential")) +} diff --git a/host/src/harness/mod.rs b/host/src/harness/mod.rs index b95d1cf..246bb37 100644 --- a/host/src/harness/mod.rs +++ b/host/src/harness/mod.rs @@ -1,4 +1,5 @@ //! Durable V8 harness, host-side SQLite storage, and world tool operations. +mod credentials; mod environment; use crate::{exec::Exec, world::World}; use deno_core::{JsRuntime, OpState, RuntimeOptions, op2}; @@ -78,6 +79,9 @@ deno_core::extension!( storage, ops = [ op_sql, + credentials::op_credential_requests, + credentials::op_model_proxy, + credentials::op_credential_next, environment::op_file, environment::op_exec, environment::op_exec_next, @@ -112,6 +116,18 @@ pub async fn run_with_exec(world: World, exec: Arc) -> anyhow::Result< /// Evaluate a bundled harness module with the same storage and tool operations as the console. /// The caller must use a current-thread Tokio runtime. pub async fn run_module(world: World, exec: Arc, source: &str) -> anyhow::Result<()> { + let cred = Arc::new(crate::cred::store::Cred::open(&world.host_dir)?); + run_module_with_credentials(world, exec, cred, source).await +} + +/// Run a harness with the credentials handle shared by the host API. +pub async fn run_module_with_credentials( + world: World, + exec: Arc, + cred: Arc, + source: &str, +) -> anyhow::Result<()> { + let proxy = credentials::proxy(&cred)?; let mut runtime = JsRuntime::new(RuntimeOptions { extensions: vec![ deno_telemetry::deno_telemetry::init(), @@ -162,11 +178,11 @@ pub async fn run_module(world: World, exec: Arc, source: &str) -> anyh deno_permissions::RuntimePermissionDescriptorParser::new(sys_traits::impls::RealSys), ))); runtime.execute_script("bootstrap.js", include_str!("../../js/bootstrap.js"))?; - let env: serde_json::Map = ["PI_PROXY_BASE_URL", "PI_PROXY_API_KEY"] - .into_iter() - .filter_map(|key| std::env::var(key).ok().map(|v| (key.to_owned(), json!(v)))) - .collect(); - runtime.execute_script("env.js", format!("process.env = {};", Value::Object(env)))?; + runtime + .op_state() + .borrow_mut() + .put(credentials::Notifications::new(&cred)); + runtime.op_state().borrow_mut().put(cred); runtime .op_state() .borrow_mut() @@ -186,11 +202,26 @@ pub async fn run_module(world: World, exec: Arc, source: &str) -> anyh .load_main_es_module_from_code(&specifier, source.to_owned()) .await?; let result = runtime.mod_evaluate(module); - runtime - .with_event_loop_promise(result, Default::default()) - .await?; - runtime.run_event_loop(Default::default()).await?; - Ok(()) + let result = async { + runtime + .with_event_loop_promise(result, Default::default()) + .await?; + runtime.run_event_loop(Default::default()).await?; + Ok::<_, anyhow::Error>(()) + } + .await; + result.map_err(|error| { + let mut text = error.to_string(); + if let Some(key) = proxy + .as_ref() + .and_then(|v| v.get("api_key")) + .and_then(Value::as_str) + && !key.is_empty() + { + text = text.replace(key, "[redacted]"); + } + anyhow::anyhow!(text) + }) } /// Open a world and resume its durable root conversation. diff --git a/host/tests/durable.rs b/host/tests/durable.rs new file mode 100644 index 0000000..3f38086 --- /dev/null +++ b/host/tests/durable.rs @@ -0,0 +1,325 @@ +//! Credential decisions wake an idle faux-model conversation through durable tasks. +use sausage::{ + cred::{ + items::Item, + requests::{GrantRequest, Overrides}, + store::Cred, + types::Caller, + }, + harness::{run_module, run_module_with_credentials}, + world::World, +}; +use std::sync::Arc; + +#[tokio::test(flavor = "current_thread")] +async fn restart_child() -> anyhow::Result<()> { + let Ok(dir) = std::env::var("DURABLE_RESTART_DIR") else { + return Ok(()); + }; + let dir = std::path::Path::new(&dir); + let source = format!( + "globalThis.expectedState = 'approved';\n{}", + include_str!("../js/durable-test-bundle.js") + ); + run_module( + World::open(dir)?, + sausage::process::exec(World::open(dir)?)?, + &source, + ) + .await +} + +#[test] +fn sigkill_preserves_request_wait() -> anyhow::Result<()> { + use std::{ + process::Command, + time::{Duration, Instant}, + }; + let dir = std::env::temp_dir().join(format!("sausage-durable-restart-{}", std::process::id())); + let world = World::open(&dir)?; + let cred = Cred::open(&world.host_dir)?; + let admin = Caller { + pid: 0, + program: "test".into(), + conversations: vec![], + }; + let item = cred.create_item( + Item { + id: String::new(), + name: "github".into(), + version: 0, + free_use: false, + rules: vec![], + validate_js: None, + transform_js: "export default (ctx) => ctx.request".into(), + fields: vec![], + }, + &admin, + "test", + )?; + let mut child = Command::new(std::env::current_exe()?) + .args(["--exact", "restart_child", "--nocapture"]) + .env("DURABLE_RESTART_DIR", &dir) + .spawn()?; + let deadline = Instant::now() + Duration::from_secs(30); + let conversation = loop { + if let Ok(id) = std::fs::read_to_string(dir.join("world/conversation")) + && !id.is_empty() + { + break id; + } + if Instant::now() > deadline { + child.kill()?; + child.wait()?; + anyhow::bail!("Conversation did not start"); + } + std::thread::yield_now(); + }; + let caller = Caller { + conversations: vec![conversation], + ..admin + }; + let id = cred.file_request( + &caller, + "restart", + GrantRequest { + items: vec![item.id], + duration_secs: None, + max_uses: None, + validator: None, + }, + )?; + let db = rusqlite::Connection::open(dir.join("host/harness.sqlite"))?; + loop { + let count: i64 = db.query_row( + "SELECT count(*) FROM tasks WHERE json_extract(kind, '$')='sausage.credential.wait'", + [], + |r| r.get(0), + )?; + if count == 1 { + break; + } + if Instant::now() > deadline { + child.kill()?; + child.wait()?; + anyhow::bail!("Durable wait did not start"); + } + std::thread::yield_now(); + } + child.kill()?; + child.wait()?; + cred.approve(&id, "yes", Overrides::default(), Some("test"))?; + for _ in 0..2 { + let mut resumed = Command::new(std::env::current_exe()?) + .args(["--exact", "restart_child", "--nocapture"]) + .env("DURABLE_RESTART_DIR", &dir) + .spawn()?; + let deadline = Instant::now() + Duration::from_secs(30); + loop { + if let Some(status) = resumed.try_wait()? { + assert!(status.success()); + break; + } + if Instant::now() > deadline { + resumed.kill()?; + resumed.wait()?; + anyhow::bail!("Restart did not finish"); + } + std::thread::yield_now(); + } + } + drop(db); + std::fs::remove_dir_all(dir)?; + Ok(()) +} + +#[tokio::test(flavor = "current_thread")] +async fn proxy_child() -> anyhow::Result<()> { + let Ok(dir) = std::env::var("DURABLE_PROXY_DIR") else { + return Ok(()); + }; + let dir = std::path::Path::new(&dir); + let source = format!( + "globalThis.proxyOnly = true; const proxy = Deno.core.ops.op_model_proxy(); if (proxy.base_url !== 'https://proxy.invalid' || proxy.api_key !== 'faux-private-token') throw new Error('Wrong proxy item');\n{}", + include_str!("../js/durable-test-bundle.js") + ); + run_module( + World::open(dir)?, + sausage::process::exec(World::open(dir)?)?, + &source, + ) + .await?; + let error = run_module( + World::open(dir)?, + sausage::process::exec(World::open(dir)?)?, + "throw new Error(Deno.core.ops.op_model_proxy().api_key)", + ) + .await + .unwrap_err(); + assert!(!error.to_string().contains("faux-private-token")); + assert!(error.to_string().contains("[redacted]")); + Ok(()) +} + +#[test] +fn proxy_bootstrap_once() -> anyhow::Result<()> { + let dir = std::env::temp_dir().join(format!("sausage-durable-proxy-{}", std::process::id())); + for start in 0..2 { + let status = std::process::Command::new(std::env::current_exe()?) + .args(["--exact", "proxy_child", "--nocapture"]) + .env("DURABLE_PROXY_DIR", &dir) + .env( + "PI_PROXY_BASE_URL", + if start == 0 { + "https://proxy.invalid" + } else { + "https://ignored.invalid" + }, + ) + .env( + "PI_PROXY_API_KEY", + if start == 0 { + "faux-private-token" + } else { + "ignored-token" + }, + ) + .status()?; + assert!(status.success()); + } + let cred = Cred::open(&dir.join("host"))?; + assert_eq!( + cred.item_list()? + .iter() + .filter(|i| i.name == "llm-proxy") + .count(), + 1 + ); + for file in [ + "host/cred.sqlite", + "host/cred.sqlite-wal", + "host/harness.sqlite", + "host/harness.sqlite-wal", + ] { + if let Ok(bytes) = std::fs::read(dir.join(file)) { + assert!( + !bytes + .windows(b"faux-private-token".len()) + .any(|w| w == b"faux-private-token") + ); + } + } + assert!(!dir.join("world/conversation").exists()); + drop(cred); + std::fs::remove_dir_all(dir)?; + Ok(()) +} + +#[tokio::test(flavor = "current_thread")] +async fn decisions_wake_idle_conversation() -> anyhow::Result<()> { + for state in ["approved", "denied", "expired"] { + let dir = + std::env::temp_dir().join(format!("sausage-durable-{}-{state}", std::process::id())); + let world = World::open(&dir)?; + let cred = Arc::new(Cred::open(&world.host_dir)?); + let admin = Caller { + pid: 0, + program: "test".into(), + conversations: vec![], + }; + let item = cred.create_item( + Item { + id: String::new(), + name: "github".into(), + version: 0, + free_use: false, + rules: vec![], + validate_js: None, + transform_js: "export default (ctx) => ctx.request".into(), + fields: vec![], + }, + &admin, + "test", + )?; + cred.file_request( + &admin, + "program", + GrantRequest { + items: vec![item.id.clone()], + duration_secs: None, + max_uses: None, + validator: None, + }, + )?; + let source = format!( + "globalThis.expectedState = {state:?};\n{}", + include_str!("../js/durable-test-bundle.js") + ); + let decide = async { + let conversation = loop { + if let Ok(id) = std::fs::read_to_string(dir.join("world/conversation")) + && !id.is_empty() + { + break id; + } + tokio::task::yield_now().await; + }; + let caller = Caller { + conversations: vec![conversation], + ..admin + }; + let id = cred.file_request( + &caller, + "test", + GrantRequest { + items: vec![item.id], + duration_secs: None, + max_uses: None, + validator: None, + }, + )?; + let harness_db = rusqlite::Connection::open(dir.join("host/harness.sqlite"))?; + loop { + let count: i64 = harness_db.query_row( + "SELECT count(*) FROM tasks WHERE json_extract(kind, '$')='sausage.credential.wait'", + [], + |r| r.get(0), + )?; + if count == 1 { + break; + } + tokio::task::yield_now().await; + } + match state { + "approved" => cred.approve(&id, "yes", Overrides::default(), Some("test"))?, + "denied" => cred.deny(&id, "no", Some("test"))?, + _ => { + let db = rusqlite::Connection::open(dir.join("host/cred.sqlite"))?; + db.execute("UPDATE requests SET expires=0 WHERE id=?", [&id])?; + } + } + Ok::<_, anyhow::Error>(()) + }; + let exec = sausage::process::exec(World::open(&dir)?)?; + tokio::time::timeout(std::time::Duration::from_secs(20), async { + let (a, b) = tokio::join!( + run_module_with_credentials(world, Arc::clone(&exec), cred.clone(), &source), + decide + ); + a?; + b?; + Ok::<_, anyhow::Error>(()) + }) + .await??; + let db = rusqlite::Connection::open(dir.join("host/harness.sqlite"))?; + let tasks: i64 = db.query_row( + "SELECT count(*) FROM tasks WHERE json_extract(kind, '$')='sausage.credential.wait'", + [], + |r| r.get(0), + )?; + assert_eq!(tasks, 1, "Program requests must create no durable task"); + drop(db); + std::fs::remove_dir_all(dir)?; + } + Ok(()) +} From 940ae61af6b4b13b40dc7bd12190e010f5e599c7 Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 6 Nov 2026 21:17:52 +0000 Subject: [PATCH 04/12] cred: blind RSA signatures and stage T28 security regressions (WIP) --- Cargo.lock | 1 + host/Cargo.toml | 2 +- host/src/cred/keys.rs | 69 +++++++++- host/src/cred/oauth2.rs | 168 ++++++++++++++++++---- host/src/cred/v8.rs | 29 ++-- host/tests/cred_oauth2.rs | 245 +++++++++++++++++++++++++++++---- host/tests/cred_v8_security.rs | 56 ++++++++ 7 files changed, 503 insertions(+), 67 deletions(-) create mode 100644 host/tests/cred_v8_security.rs diff --git a/Cargo.lock b/Cargo.lock index 7d50be6..2b33d4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7843,6 +7843,7 @@ version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" dependencies = [ + "serde", "zeroize_derive", ] diff --git a/host/Cargo.toml b/host/Cargo.toml index 88863a7..553f27c 100644 --- a/host/Cargo.toml +++ b/host/Cargo.toml @@ -34,7 +34,7 @@ serde = { version = "1.0.229", features = ["derive"] } serde_yaml_ng = "0.10.0" rustls = "0.23" chacha20poly1305 = "0.10" -zeroize = "1" +zeroize = { version = "1", features = ["serde"] } hex = "0.4" http = "1" url = "2" diff --git a/host/src/cred/keys.rs b/host/src/cred/keys.rs index 78dee7e..fa57937 100644 --- a/host/src/cred/keys.rs +++ b/host/src/cred/keys.rs @@ -190,12 +190,7 @@ pub(super) fn sign_key(key: &Key, format: &str, payload: &[u8]) -> Result if format == "rsa-sha2-512" { - k.sign(rsa::Pkcs1v15Sign::new::(), &Sha512::digest(payload)) - } else { - k.sign(rsa::Pkcs1v15Sign::new::(), &Sha256::digest(payload)) - } - .map_err(|_| invalid_key())?, + Key::Rsa(k) => rsa_signature(k, format, payload, &mut rsa::rand_core::OsRng)?, Key::Mac(k) => { macro_rules! mac { ($h:ty) => {{ @@ -212,6 +207,28 @@ pub(super) fn sign_key(key: &Key, format: &str, payload: &[u8]) -> Result Result> { + if format == "rsa-sha2-512" { + key.sign_with_rng( + rng, + rsa::Pkcs1v15Sign::new::(), + &Sha512::digest(payload), + ) + } else { + key.sign_with_rng( + rng, + rsa::Pkcs1v15Sign::new::(), + &Sha256::digest(payload), + ) + } + .map_err(|_| invalid_key()) +} + fn string(out: &mut Vec, bytes: &[u8]) { out.extend_from_slice(&(bytes.len() as u32).to_be_bytes()); out.extend_from_slice(bytes); @@ -303,3 +320,43 @@ pub(super) fn public(key: &Key, output: &str) -> Result { _ => return Err(error("invalid_params", "unknown public key output")), }) } + +#[cfg(test)] +mod blinding_tests { + use super::*; + use rsa::rand_core::{CryptoRng, OsRng, RngCore}; + + struct Counting(usize); + impl CryptoRng for Counting {} + impl RngCore for Counting { + fn next_u32(&mut self) -> u32 { + self.0 += 4; + OsRng.next_u32() + } + fn next_u64(&mut self) -> u64 { + self.0 += 8; + OsRng.next_u64() + } + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0 += dest.len(); + OsRng.fill_bytes(dest); + } + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> std::result::Result<(), rsa::rand_core::Error> { + self.0 += dest.len(); + OsRng.try_fill_bytes(dest) + } + } + #[test] + fn rsa_uses_blinding_randomness() { + let key = rsa::RsaPrivateKey::new(&mut OsRng, 1024).unwrap(); + let mut rng = Counting(0); + for format in ["rs256", "rsa-sha2-256", "rsa-sha2-512"] { + let before = rng.0; + rsa_signature(&key, format, b"synthetic", &mut rng).unwrap(); + assert!( + rng.0 > before, + "RSA signing must consume blinding randomness" + ); + } + } +} diff --git a/host/src/cred/oauth2.rs b/host/src/cred/oauth2.rs index 6ad2be0..a6f49aa 100644 --- a/host/src/cred/oauth2.rs +++ b/host/src/cred/oauth2.rs @@ -1,6 +1,11 @@ -//! OAuth2 refresh exchange and a process-local cache keyed by item and version. +//! OAuth2 refresh exchange, endpoint policy, and a revision-aware process-local cache. +use super::{ + items::{Item, rule_matches}, + types::FieldType, +}; use std::{ - collections::BTreeMap, + collections::{BTreeMap, BTreeSet}, + sync::Mutex, time::{Duration, Instant}, }; use zeroize::Zeroizing; @@ -14,13 +19,18 @@ impl std::fmt::Display for Error { } impl std::error::Error for Error {} -/// HTTP adapter. Implementations must reject unsuccessful HTTP status codes. +/// A single HTTP exchange. Adapters must honor the deadline and never follow redirects. pub trait Http: Sync { - fn send( + fn send_once( &self, request: &Request, deadline: Instant, - ) -> impl std::future::Future>, Error>> + Send; + ) -> impl std::future::Future> + Send; +} +/// The status and body of one response, without any redirect exchange. +pub struct Response { + pub status: http::StatusCode, + pub body: Zeroizing>, } /// Contains credentials. Deliberately does not implement Debug or Serialize. pub struct Request { @@ -44,22 +54,39 @@ pub fn request( { return Err(Error); } - let body = url::form_urlencoded::Serializer::new(String::new()) - .append_pair("grant_type", "refresh_token") - .append_pair("refresh_token", refresh_token) - .append_pair("client_id", client_id) - .append_pair("client_secret", client_secret) - .finish(); + let body = Zeroizing::new( + url::form_urlencoded::Serializer::new(String::new()) + .append_pair("grant_type", "refresh_token") + .append_pair("refresh_token", refresh_token) + .append_pair("client_id", client_id) + .append_pair("client_secret", client_secret) + .finish(), + ); Ok(Request { - url: token_url.into(), + url: target.into(), method: "POST", headers: vec![ ("Content-Type", "application/x-www-form-urlencoded".into()), ("Content-Length", body.len().to_string()), ], - body: Zeroizing::new(body), + body, }) } +fn allowed(item: &Item, request: &Request) -> bool { + let Ok(target) = url::Url::parse(&request.url) else { + return false; + }; + target.scheme() == "https" + && target.username().is_empty() + && target.password().is_none() + && target.fragment().is_none() + && request.method == "POST" + && target.host_str().is_some_and(|host| { + item.rules + .iter() + .any(|rule| rule_matches(rule, target.scheme(), host, target.path(), "POST")) + }) +} #[derive(Clone)] pub struct Token { pub value: Zeroizing, @@ -69,51 +96,134 @@ pub struct Token { pub fn decode(bytes: &[u8]) -> Result { #[derive(serde::Deserialize)] struct Response { - access_token: String, + access_token: Zeroizing, token_type: String, expires_in: u64, scope: Option, } let r: Response = serde_json::from_slice(bytes).map_err(|_| Error)?; + // Validate header bytes without a second, non-zeroizing token allocation. if r.access_token.is_empty() || !r.token_type.eq_ignore_ascii_case("bearer") || r.expires_in == 0 - || http::header::HeaderValue::from_str(&format!("Bearer {}", r.access_token)).is_err() + || r.access_token + .bytes() + .any(|b| b != b'\t' && (b < 32 || b == 127)) { return Err(Error); } Ok(Token { - value: Zeroizing::new(r.access_token), + value: r.access_token, scopes: r .scope .map(|s| s.split_whitespace().map(str::to_owned).collect()), expires: Instant::now() + Duration::from_secs(r.expires_in.min(86400).saturating_sub(30)), }) } -/// The caller owns synchronization and endpoint policy. No lock crosses an HTTP call here. +#[derive(Default)] +struct State { + tokens: BTreeMap<(String, i64), Token>, + busy: BTreeSet, + epoch: u64, +} +/// No mutex guard crosses HTTP await. Clear this cache on vault lock or item changes. #[derive(Default)] pub struct Cache { - tokens: BTreeMap<(String, i64), Token>, + state: Mutex, +} +struct Flight<'a> { + cache: &'a Cache, + item: String, +} +impl Drop for Flight<'_> { + fn drop(&mut self) { + if let Ok(mut state) = self.cache.state.lock() { + state.busy.remove(&self.item); + } + } } impl Cache { - pub fn clear(&mut self) { - self.tokens.clear(); + pub fn clear(&self) -> Result<(), Error> { + let mut state = self.state.lock().map_err(|_| Error)?; + state.tokens.clear(); + state.epoch += 1; + Ok(()) } pub async fn refresh( - &mut self, - item: &str, - version: i64, + &self, + item: &Item, request: &Request, http: &impl Http, deadline: Instant, ) -> Result { - let key = (item.to_owned(), version); - if let Some(t) = self.tokens.get(&key).filter(|t| t.expires > Instant::now()) { - return Ok(t.clone()); + // Baseline preserves the old unchecked policy until the regression runs. + let _ = allowed(item, request); + if Instant::now() >= deadline { + return Err(Error); } - self.tokens.retain(|(id, _), _| id != item); - let token = decode(&http.send(request, deadline).await?)?; - self.tokens.insert(key, token.clone()); + let key = (item.id.clone(), item.version); + let epoch; + { + let mut state = self.state.lock().map_err(|_| Error)?; + if let Some(t) = state + .tokens + .get(&key) + .filter(|t| t.expires > Instant::now()) + { + return Ok(t.clone()); + } + state.tokens.retain(|(id, _), _| id != &item.id); + if !state.busy.insert(item.id.clone()) { + return Err(Error); + } + epoch = state.epoch; + } + let _flight = Flight { + cache: self, + item: item.id.clone(), + }; + let response = http.send_once(request, deadline).await?; + let token = decode(&response.body)?; + let mut state = self.state.lock().map_err(|_| Error)?; + if state.epoch != epoch || Instant::now() >= deadline { + return Err(Error); + } + state.tokens.insert(key, token.clone()); Ok(token) } + + /// Injection entry point. Replace the refresh field before any transform sees these values. + /// The caller must reserve any additional grant use before this exchange. + pub async fn fields_for_injection( + &self, + item: &Item, + mut fields: BTreeMap>, + http: &impl Http, + deadline: Instant, + ) -> Result>, Error> { + let mut refresh = item + .fields + .iter() + .filter(|f| f.field_type == FieldType::Oauth2RefreshToken); + let field = refresh.next().ok_or(Error)?; + if field.public || refresh.next().is_some() { + return Err(Error); + } + let value = |name: &str| { + fields + .get(name) + .map(|s| s.as_str()) + .filter(|s| !s.is_empty()) + .ok_or(Error) + }; + let req = request( + value("token_url")?, + value(&field.name)?, + value("client_id")?, + value("client_secret")?, + )?; + let token = self.refresh(item, &req, http, deadline).await?; + fields.insert(field.name.clone(), token.value); + Ok(fields) + } } diff --git a/host/src/cred/v8.rs b/host/src/cred/v8.rs index 3b2f1ad..f2185ff 100644 --- a/host/src/cred/v8.rs +++ b/host/src/cred/v8.rs @@ -1,6 +1,7 @@ //! Fresh, bounded V8 isolates for credential scripts. Each call owns a dedicated worker thread. use super::script::{Error, ErrorKind, Limits, Script}; use deno_core::{JsRuntime, RuntimeOptions, v8}; +use zeroize::Zeroizing; use std::{ sync::{ Arc, @@ -34,7 +35,7 @@ impl Script for V8 { limits: Limits, ) -> Result { let source = source.to_owned(); - let input = input.to_owned(); + let input = Zeroizing::new(input.to_owned()); let export = export.unwrap_or("default").to_owned(); std::thread::spawn(move || evaluate(source, input, export, limits)) .join() @@ -43,7 +44,7 @@ impl Script for V8 { } fn evaluate( source: String, - input: String, + input: Zeroizing, export: String, limits: Limits, ) -> Result { @@ -96,12 +97,13 @@ fn evaluate( runtime .execute_script("sandbox.js", BOOTSTRAP) .map_err(|_| failure(ErrorKind::Engine))?; - let input = runtime - .execute_script( - "input.js", - format!("JSON.parse({})", serde_json::to_string(&input).unwrap()), - ) - .map_err(|_| failure(ErrorKind::Syntax))?; + let input = { + deno_core::scope!(scope, &mut runtime); + v8::tc_scope!(let scope, scope); + let text = v8::String::new(scope, &input).ok_or_else(|| failure(ErrorKind::Limit))?; + let value = v8::json::parse(scope, text).ok_or_else(|| failure(ErrorKind::Syntax))?; + v8::Global::new(scope, value) + }; let spec = deno_core::ModuleSpecifier::parse("file:///credential.js").unwrap(); let module = runtime .load_main_es_module_from_code(&spec, source) @@ -197,3 +199,14 @@ globalThis.atob = value => { return out; }; "#; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn script_input_zeroizes_on_drop() { + let _: fn(String, zeroize::Zeroizing, String, Limits) -> Result = + evaluate; + } +} diff --git a/host/tests/cred_oauth2.rs b/host/tests/cred_oauth2.rs index 81f52e8..9b09c19 100644 --- a/host/tests/cred_oauth2.rs +++ b/host/tests/cred_oauth2.rs @@ -1,16 +1,36 @@ -//! Refresh form encoding, response validation, and revision-aware cache behavior. -use sausage::cred::oauth2::*; +//! OAuth endpoint policy, single-hop exchanges, cache ownership, and safe injection fields. +use sausage::cred::{items::Item, oauth2::*}; use std::{ - sync::atomic::{AtomicUsize, Ordering}, + collections::BTreeMap, + sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, + }, time::{Duration, Instant}, }; use zeroize::Zeroizing; +fn item(version: i64) -> Item { + serde_json::from_value(serde_json::json!({ + "id":"id", "name":"OAuth", "version":version, + "rules":[{"scheme":"https","hosts":["tokens.example.test"],"path_prefixes":["/token"],"methods":["POST"]}], + "transform_js":"", "fields":[{"field_id":"refresh","name":"refresh_token","public":false,"value":null,"field_type":"oauth2_refresh_token","key_type":null}] + })).unwrap() +} +fn deadline() -> Instant { + Instant::now() + Duration::from_secs(1) +} +fn ok(bytes: &[u8]) -> Response { + Response { + status: http::StatusCode::OK, + body: Zeroizing::new(bytes.to_vec()), + } +} struct Fake(AtomicUsize); impl Http for Fake { - async fn send(&self, request: &Request, _: Instant) -> Result>, Error> { + async fn send_once(&self, request: &Request, _: Instant) -> Result { assert_eq!(request.method, "POST"); self.0.fetch_add(1, Ordering::SeqCst); - Ok(Zeroizing::new(br#"{"access_token":"SYNTHETIC","token_type":"Bearer","expires_in":3600,"scope":"one two"}"#.to_vec())) + Ok(ok(br#"{"access_token":"SYNTHETIC","token_type":"Bearer","expires_in":3600,"scope":"one two"}"#)) } } #[tokio::test] @@ -28,16 +48,27 @@ async fn encoding_and_cache() { ); assert_eq!(req.headers[1].1, req.body.len().to_string()); let fake = Fake(AtomicUsize::new(0)); - let mut cache = Cache::default(); - let deadline = Instant::now() + Duration::from_secs(1); - let t = cache.refresh("id", 1, &req, &fake, deadline).await.unwrap(); + let cache = Cache::default(); + let t = cache + .refresh(&item(1), &req, &fake, deadline()) + .await + .unwrap(); assert_eq!(t.scopes.unwrap(), vec!["one", "two"]); - cache.refresh("id", 1, &req, &fake, deadline).await.unwrap(); + cache + .refresh(&item(1), &req, &fake, deadline()) + .await + .unwrap(); assert_eq!(fake.0.load(Ordering::SeqCst), 1); - cache.refresh("id", 2, &req, &fake, deadline).await.unwrap(); + cache + .refresh(&item(2), &req, &fake, deadline()) + .await + .unwrap(); assert_eq!(fake.0.load(Ordering::SeqCst), 2); - cache.clear(); - cache.refresh("id", 2, &req, &fake, deadline).await.unwrap(); + cache.clear().unwrap(); + cache + .refresh(&item(2), &req, &fake, deadline()) + .await + .unwrap(); assert_eq!(fake.0.load(Ordering::SeqCst), 3); for url in [ "http://tokens.example.test/token", @@ -51,36 +82,204 @@ async fn encoding_and_cache() { async fn expiry_and_failure() { struct Expired(AtomicUsize); impl Http for Expired { - async fn send(&self, _: &Request, _: Instant) -> Result>, Error> { + async fn send_once(&self, _: &Request, _: Instant) -> Result { self.0.fetch_add(1, Ordering::SeqCst); - Ok(Zeroizing::new( - br#"{"access_token":"SYNTHETIC","token_type":"Bearer","expires_in":1}"#.to_vec(), + Ok(ok( + br#"{"access_token":"SYNTHETIC","token_type":"Bearer","expires_in":1}"#, )) } } struct Failed; impl Http for Failed { - async fn send(&self, _: &Request, _: Instant) -> Result>, Error> { + async fn send_once(&self, _: &Request, _: Instant) -> Result { Err(Error) } } let req = request("https://tokens.example.test/token", "r", "c", "s").unwrap(); - let mut cache = Cache::default(); + let cache = Cache::default(); let http = Expired(AtomicUsize::new(0)); - let deadline = Instant::now() + Duration::from_secs(1); - cache.refresh("id", 1, &req, &http, deadline).await.unwrap(); - cache.refresh("id", 1, &req, &http, deadline).await.unwrap(); + cache + .refresh(&item(1), &req, &http, deadline()) + .await + .unwrap(); + cache + .refresh(&item(1), &req, &http, deadline()) + .await + .unwrap(); assert_eq!(http.0.load(Ordering::SeqCst), 2); assert!( cache - .refresh("id", 2, &req, &Failed, deadline) + .refresh(&item(2), &req, &Failed, deadline()) .await .is_err() ); - cache.refresh("id", 2, &req, &http, deadline).await.unwrap(); + cache + .refresh(&item(2), &req, &http, deadline()) + .await + .unwrap(); assert_eq!(http.0.load(Ordering::SeqCst), 3); } - +#[tokio::test] +async fn endpoint_policy_applies_before_http_and_cache_hits() { + let cache = Cache::default(); + let fake = Fake(AtomicUsize::new(0)); + let req = request("https://tokens.example.test/token", "r", "c", "s").unwrap(); + cache + .refresh(&item(1), &req, &fake, deadline()) + .await + .unwrap(); + for rule in [ + serde_json::json!({"scheme":"https","hosts":["wrong.example.test"],"path_prefixes":["/token"],"methods":["POST"]}), + serde_json::json!({"scheme":"http","hosts":["tokens.example.test"],"path_prefixes":["/token"],"methods":["POST"]}), + serde_json::json!({"scheme":"https","hosts":["tokens.example.test"],"path_prefixes":["/elsewhere"],"methods":["POST"]}), + serde_json::json!({"scheme":"https","hosts":["tokens.example.test"],"path_prefixes":["/token"],"methods":["GET"]}), + ] { + let mut denied = item(1); + denied.rules = vec![serde_json::from_value(rule).unwrap()]; + assert!( + cache + .refresh(&denied, &req, &fake, deadline()) + .await + .is_err() + ); + denied.version = 2; + assert!( + cache + .refresh(&denied, &req, &fake, deadline()) + .await + .is_err() + ); + } + for url in [ + "http://tokens.example.test/token", + "https://user@tokens.example.test/token", + "https://tokens.example.test/token#x", + "https://wrong.example.test/token", + ] { + let mut altered = request("https://tokens.example.test/token", "r", "c", "s").unwrap(); + altered.url = url.into(); + assert!( + cache + .refresh(&item(1), &altered, &fake, deadline()) + .await + .is_err() + ); + } + let mut altered = req; + altered.method = "GET"; + assert!( + cache + .refresh(&item(1), &altered, &fake, deadline()) + .await + .is_err() + ); + assert_eq!(fake.0.load(Ordering::SeqCst), 1); +} +#[tokio::test] +async fn rejects_redirects_without_a_second_exchange() { + struct Redirect(AtomicUsize); + impl Http for Redirect { + async fn send_once(&self, _: &Request, _: Instant) -> Result { + self.0.fetch_add(1, Ordering::SeqCst); + let mut response = + ok(br#"{"access_token":"SYNTHETIC","token_type":"Bearer","expires_in":3600}"#); + response.status = http::StatusCode::FOUND; + Ok(response) + } + } + let http = Redirect(AtomicUsize::new(0)); + let cache = Cache::default(); + let req = request("https://tokens.example.test/token", "r", "c", "s").unwrap(); + assert!( + cache + .refresh(&item(1), &req, &http, deadline()) + .await + .is_err() + ); + assert_eq!(http.0.load(Ordering::SeqCst), 1); +} +#[tokio::test] +async fn injection_replaces_the_refresh_field() { + let fields: BTreeMap<_, _> = [ + ("token_url", "https://tokens.example.test/token"), + ("refresh_token", "REFRESH"), + ("client_id", "CLIENT"), + ("client_secret", "SECRET"), + ] + .into_iter() + .map(|(k, v)| (k.into(), Zeroizing::new(v.into()))) + .collect(); + let fake = Fake(AtomicUsize::new(0)); + let result = Cache::default() + .fields_for_injection(&item(1), fields, &fake, deadline()) + .await + .unwrap(); + assert!(result["refresh_token"].as_str() == "SYNTHETIC"); + assert!(result["client_secret"].as_str() == "SECRET"); +} +#[tokio::test] +async fn inflight_releases_the_lock_and_cleans_up() { + struct Blocking { + started: tokio::sync::Notify, + resume: tokio::sync::Notify, + } + impl Http for Blocking { + async fn send_once(&self, _: &Request, _: Instant) -> Result { + self.started.notify_one(); + self.resume.notified().await; + Ok(ok( + br#"{"access_token":"SYNTHETIC","token_type":"Bearer","expires_in":3600}"#, + )) + } + } + for clear in [false, true] { + let cache = Arc::new(Cache::default()); + let http = Arc::new(Blocking { + started: tokio::sync::Notify::new(), + resume: tokio::sync::Notify::new(), + }); + let task = tokio::spawn({ + let cache = cache.clone(); + let http = http.clone(); + async move { + let req = request("https://tokens.example.test/token", "r", "c", "s").unwrap(); + cache + .refresh(&item(1), &req, http.as_ref(), deadline()) + .await + } + }); + tokio::time::timeout(Duration::from_secs(1), http.started.notified()) + .await + .unwrap(); + let req = request("https://tokens.example.test/token", "r", "c", "s").unwrap(); + let fake = Fake(AtomicUsize::new(0)); + assert!( + cache + .refresh(&item(1), &req, &fake, deadline()) + .await + .is_err() + ); + let mut other = item(1); + other.id = "other".into(); + cache + .refresh(&other, &req, &fake, deadline()) + .await + .unwrap(); + if clear { + cache.clear().unwrap(); + http.resume.notify_one(); + assert!(task.await.unwrap().is_err()); + } else { + task.abort(); + assert!(matches!(task.await, Err(error) if error.is_cancelled())); + } + cache + .refresh(&item(1), &req, &fake, deadline()) + .await + .unwrap(); + assert_eq!(fake.0.load(Ordering::SeqCst), 2); + } +} #[test] fn validation() { for data in [ diff --git a/host/tests/cred_v8_security.rs b/host/tests/cred_v8_security.rs new file mode 100644 index 0000000..ae8b085 --- /dev/null +++ b/host/tests/cred_v8_security.rs @@ -0,0 +1,56 @@ +//! Crash regression for a single large V8 allocation. The child contains native V8 aborts. +use sausage::cred::{ + script::{Limits, Script}, + v8::V8, +}; + +#[test] +fn removes_bootstrap_capabilities_and_clocks() { + let result = V8.evaluate( + "export default () => [typeof WebAssembly,typeof SharedArrayBuffer,typeof Atomics,typeof __infra,typeof Intl,typeof queueMicrotask]", + "null", None, Limits { max_time_ms: Some(1000), ..Limits::default() }, + ).unwrap(); + assert_eq!( + result, + "[\"undefined\",\"undefined\",\"undefined\",\"undefined\",\"undefined\",\"undefined\"]" + ); +} + +#[test] +fn flat_string_child() { + if std::env::var_os("T28_FLAT_STRING_CHILD").is_none() { + return; + } + let bits = std::env::var("T28_FLAT_STRING_BITS").unwrap_or_else(|_| "28".into()); + assert!(matches!(bits.as_str(), "27" | "28")); + let result = V8.evaluate( + &format!("export default () => 'x'.repeat(2**{bits}).indexOf('y')"), + "null", + None, + Limits { + max_time_ms: Some(1000), + ..Limits::default() + }, + ); + assert!( + result.is_err(), + "the flat string bypassed the configured heap budget" + ); +} + +#[test] +fn flat_string_does_not_abort() { + for bits in ["27", "28"] { + let output = std::process::Command::new(std::env::current_exe().unwrap()) + .args(["--exact", "flat_string_child", "--nocapture"]) + .env("T28_FLAT_STRING_CHILD", "1") + .env("T28_FLAT_STRING_BITS", bits) + .output() + .unwrap(); + assert!( + output.status.success(), + "the script worker aborted or failed at 2**{bits} bytes: {}", + output.status + ); + } +} From b3d3558b312065b6d281f0c67ffc8c6cb0b8aa84 Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 6 Nov 2026 21:31:50 +0000 Subject: [PATCH 05/12] cred: stage T27 core fixes and security regressions before T26 merge (WIP) --- host/src/cred/edits.rs | 11 +- host/src/cred/grants.rs | 79 +++++--- host/src/cred/inject.rs | 60 +++--- host/src/cred/items.rs | 81 ++++++-- host/src/cred/schema.rs | 7 +- host/src/cred/types.rs | 6 +- host/src/cred/webauthn.rs | 326 ++++++++++++------------------- host/tests/cred.rs | 27 +-- host/tests/cred_authorization.rs | 36 ++++ host/tests/cred_challenges.rs | 26 +++ host/tests/cred_core.rs | 22 ++- host/tests/cred_edits.rs | 28 +-- host/tests/cred_grants.rs | 21 +- host/tests/cred_policy.rs | 44 +++++ host/tests/cred_presentation.rs | 16 ++ host/tests/cred_regressions.rs | 45 +++-- host/tests/cred_replay.rs | 36 ++-- host/tests/cred_security.rs | 53 +++++ host/tests/cred_storage.rs | 30 +++ host/tests/cred_summary.rs | 6 +- 20 files changed, 594 insertions(+), 366 deletions(-) create mode 100644 host/tests/cred_authorization.rs create mode 100644 host/tests/cred_challenges.rs create mode 100644 host/tests/cred_policy.rs create mode 100644 host/tests/cred_presentation.rs create mode 100644 host/tests/cred_security.rs create mode 100644 host/tests/cred_storage.rs diff --git a/host/src/cred/edits.rs b/host/src/cred/edits.rs index e369474..21d7e7d 100644 --- a/host/src/cred/edits.rs +++ b/host/src/cred/edits.rs @@ -564,10 +564,13 @@ impl super::Cred { self.file_payload(caller, key, serde_json::json!({"edit":edit,"diff":diff})) } /// Replace a pending edit's base version after the UI reviews the current item. - pub fn resolve_stale(&self, id: &str, base_version: i64) -> Result<()> { + pub fn resolve_stale(&self, id: &str, base_version: i64, caller: &Caller, proof: impl Into) -> Result<()> { let mut s = self.access()?; let tx = s.db.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; + let binding = super::webauthn::Binding::mutation(super::webauthn::Mutation::ResolveStale, + &serde_json::json!({"request_id":id,"base_version":base_version}))?; + let approver = proof.into().check(&tx, &binding)?; let (payload, state): (String, String) = tx.query_row("SELECT payload,state FROM requests WHERE id=?", [id], |r| { Ok((r.get(0)?, r.get(1)?)) @@ -595,10 +598,14 @@ impl super::Cred { payload["edit"] = serde_json::to_value(edit)?; payload["diff"] = serde_json::to_value(diff)?; } + let encoded = serde_json::to_string(&payload)?; tx.execute( "UPDATE requests SET payload=?2 WHERE id=?1", - params![id, serde_json::to_string(&payload)?], + params![id, encoded], )?; + audit::record(&tx, "request.resolve_stale", caller, + payload.get("edit").or_else(|| payload.get("revert")).and_then(|p| p.get("item")).and_then(|v| v.as_str()), approver.as_deref())?; + tx.execute("UPDATE audit SET payload_sha256=?1 WHERE id=?2", params![super::webauthn::digest(encoded.as_bytes()), tx.last_insert_rowid()])?; tx.commit()?; Ok(()) } diff --git a/host/src/cred/grants.rs b/host/src/cred/grants.rs index 3d04654..27da8c2 100644 --- a/host/src/cred/grants.rs +++ b/host/src/cred/grants.rs @@ -24,7 +24,9 @@ pub struct Grant { } pub(crate) fn list(db: &Connection) -> Result> { let mut q=db.prepare("SELECT id,items,subject,exp,max_uses,uses,revoked,validator,note FROM grants ORDER BY rowid")?; - Ok(q.query_map([], |r| { + Ok(q.query_map([], read)?.collect::>()?) +} +fn read(r: &rusqlite::Row<'_>) -> rusqlite::Result { Ok(Grant { id: r.get(0)?, items: serde_json::from_str(&r.get::<_, String>(1)?) @@ -42,8 +44,10 @@ pub(crate) fn list(db: &Connection) -> Result> { validator: r.get(7)?, note: r.get(8)?, }) - })? - .collect::>()?) +} +fn active(db: &Connection, item: &str, caller: &Caller) -> Result> { + let mut q = db.prepare("SELECT id,items,subject,exp,max_uses,uses,revoked,validator,note FROM grants WHERE revoked=0 AND (exp IS NULL OR exp>?1) AND (max_uses IS NULL OR uses>()?) } pub(crate) fn insert( db: &Connection, @@ -53,7 +57,7 @@ pub(crate) fn insert( ) -> Result<()> { validate(db, grant)?; db.execute( - "INSERT INTO grants VALUES(?1,?2,?3,?4,?5,0,0,?6,?7)", + "INSERT INTO grants(id,items,subject,exp,max_uses,uses,revoked,validator,note) VALUES(?1,?2,?3,?4,?5,0,0,?6,?7)", params![ grant.id, serde_json::to_string(&grant.items)?, @@ -92,8 +96,9 @@ impl Cred { &self, mut grant: Grant, caller: &Caller, - approver: Option<&str>, + proof: impl Into, ) -> Result { + let binding = super::webauthn::Binding::mutation(super::webauthn::Mutation::GrantCreate, &grant)?; grant.id = seal::identity(); grant.uses = 0; grant.revoked = false; @@ -102,7 +107,8 @@ impl Cred { let mut s = self.access()?; let tx = s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; - insert(&tx, &grant, caller, approver)?; + let approver = proof.into().check(&tx, &binding)?; + insert(&tx, &grant, caller, approver.as_deref())?; tx.commit()?; Ok(grant) } @@ -115,23 +121,45 @@ impl Cred { .find(|g| g.id == id) .ok_or(Error("grant_missing")) } + /// The harness supplies every conversation in the subtree, not only its root. pub fn revoke_subjects( &self, subjects: &[String], caller: &Caller, - approver: Option<&str>, + proof: impl Into, ) -> Result<()> { let mut s = self.access()?; - let tx = s.db.transaction()?; + let tx = s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; + let binding = super::webauthn::Binding::mutation(super::webauthn::Mutation::RevokeSubjects, &subjects)?; + let approver = proof.into().check(&tx, &binding)?; for subject in subjects { tx.execute( - "UPDATE grants SET revoked=1 WHERE subject=?", + "UPDATE grants SET revoked=1,revoked_at=COALESCE(revoked_at,unixepoch()) WHERE subject=?", [serde_json::to_string(&Subject::Conversation( subject.clone(), ))?], )?; } - audit::record(&tx, "grant.revoke", caller, None, approver)?; + audit::record(&tx, "grant.revoke", caller, None, approver.as_deref())?; + tx.commit()?; + Ok(()) + } + /// Removing access needs no assertion, including after passkey registration. + pub fn revoke_grant(&self, id: &str, caller: &Caller) -> Result<()> { + let mut s = self.access()?; + let tx = s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; + if tx.execute("UPDATE grants SET revoked=1,revoked_at=COALESCE(revoked_at,unixepoch()) WHERE id=?", [id])? != 1 { + return Err(Error("grant_missing")); + } + audit::record(&tx, "grant.revoke", caller, None, None)?; + tx.commit()?; + Ok(()) + } + pub fn revoke_program(&self, program: &str, caller: &Caller) -> Result<()> { + let mut s = self.access()?; + let tx = s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; + tx.execute("UPDATE grants SET revoked=1,revoked_at=COALESCE(revoked_at,unixepoch()) WHERE subject=?", [serde_json::to_string(&Subject::Program(program.into()))?])?; + audit::record(&tx, "grant.revoke", caller, None, None)?; tx.commit()?; Ok(()) } @@ -139,32 +167,23 @@ impl Cred { &self, item: &super::items::Item, caller: &Caller, - ) -> Result> { + ) -> Result, serde_json::Value, i64)>> { let mut s = self.access()?; let master = s.master.clone(); let tx = s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; - let grant = list(&tx)?.into_iter().find(|g| { - g.items.iter().any(|i| i == &item.id) - && g.subject.covers(caller) - && !g.revoked - && g.exp.is_none_or(|e| e > now()) - && g.max_uses.is_none_or(|m| g.uses < m) - }); - if let Some(mut g) = grant { - if super::items::load(&tx, &item.id)?.version != item.version { - return Err(Error("stale")); - } - let credential = super::items::credential(&tx, &master, item, true)?; + let mut grant = if item.free_use { None } else { active(&tx, &item.id, caller)?.into_iter().next() }; + if !item.free_use && grant.is_none() { return Ok(None); } + if super::items::load(&tx, &item.id)?.version != item.version { return Err(Error("stale")); } + let credential = super::items::credential(&tx, &master, item, true)?; + if let Some(g) = &mut grant { let changed=tx.execute("UPDATE grants SET uses=uses+1 WHERE id=?1 AND revoked=0 AND (exp IS NULL OR exp>?2) AND (max_uses IS NULL OR uses bool { - item.rules.iter().any(|r| { - super::items::rule_matches( + matches_rules(&item.rules, p) +} +fn matches_rules(rules: &[super::items::Rule], p: &Parts) -> bool { + if !safe_uri(&p.uri) { return false; } + rules.iter().any(|r| { + super::items::rule_matches_port( r, p.uri.scheme_str().unwrap_or(""), p.uri.host().unwrap_or(""), p.uri.path(), p.method.as_str(), + p.uri.port_u16(), ) }) } +fn safe_uri(uri: &http::Uri) -> bool { + uri.authority().is_some_and(|a| !a.as_str().contains('@')) + && super::items::safe_path(uri.path()) +} fn request(p: &Parts) -> Result { let mut headers = Vec::new(); for (name, value) in &p.headers { @@ -45,17 +54,20 @@ impl Cred { caller: &Caller, script: &dyn Script, ) -> Result { - let candidates: Vec<_> = self - .item_list()? - .into_iter() - .filter(|i| matches(i, &parts)) - .collect(); + if !safe_uri(&parts.uri) { return Err(Error("invalid_url")); } + let candidates: Vec<_> = { + let s = self.access()?; + s.rules.iter().filter(|(_, (_, rules))| matches_rules(rules, &parts)) + .map(|(id, (version, _))| (id.clone(), *version)).collect() + }; if candidates.len() > 1 { return Err(Error("ambiguous_item")); } - let Some(item) = candidates.into_iter().next() else { + let Some((id, version)) = candidates.into_iter().next() else { return Ok(Outcome::Forward(parts)); }; + let item = self.item_get(&id)?; + if item.version != version { return Err(Error("stale")); } let original_request = request(&parts)?; if item .fields @@ -64,13 +76,11 @@ impl Cred { { return Err(Error("ssh_item")); } - let prepared = if item.free_use { - Some((None, self.credential(&item, true)?)) - } else { - self.reserve(&item, caller)? - .map(|(grant, credential)| (Some(grant), credential)) - }; - let Some((grant, secret_credential)) = prepared else { + if item.fields.iter().any(|f| f.field_type == super::types::FieldType::Oauth2RefreshToken) { + return Err(Error("oauth2_item")); + } + let prepared = self.reserve(&item, caller)?; + let Some((grant, secret_credential, audit_id)) = prepared else { let request = self.file_request( caller, &format!("inject:{}", item.id), @@ -142,10 +152,12 @@ impl Cred { .get("value") .and_then(Value::as_str) .ok_or(Error("transform"))?; + let mut value = http::HeaderValue::from_str(value).map_err(|_| Error("transform"))?; + value.set_sensitive(true); new.append( http::header::HeaderName::from_bytes(name.as_bytes()) .map_err(|_| Error("transform"))?, - http::HeaderValue::from_str(value).map_err(|_| Error("transform"))?, + value, ); } parts.headers = new; @@ -154,19 +166,13 @@ impl Cred { if !matches(&item, &parts) { return Err(Error("rule_recheck")); } + let authority = parts.uri.authority().ok_or(Error("rule_recheck"))?; + parts.headers.insert(http::header::HOST, + http::HeaderValue::from_str(authority.as_str()).map_err(|_| Error("rule_recheck"))?); Ok(()) })(); - super::audit::record( - &self.access()?.db, - if result.is_ok() { - "fetch.use" - } else { - "fetch.denied" - }, - caller, - Some(&item.id), - None, - )?; + self.access()?.db.execute("UPDATE audit SET event=?1 WHERE id=?2", + rusqlite::params![if result.is_ok() { "fetch.use" } else { "fetch.denied" }, audit_id])?; result?; Ok(Outcome::Forward(parts)) } diff --git a/host/src/cred/items.rs b/host/src/cred/items.rs index 4ba8579..2e5ef07 100644 --- a/host/src/cred/items.rs +++ b/host/src/cred/items.rs @@ -10,12 +10,25 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Rule { pub scheme: String, + #[serde(default)] + pub port: Option, pub hosts: Vec, pub path_prefixes: Vec, pub methods: Option>, } +/// Match a request on the scheme's default port. pub fn rule_matches(r: &Rule, scheme: &str, host: &str, path: &str, method: &str) -> bool { - r.scheme.eq_ignore_ascii_case(scheme) + rule_matches_port(r, scheme, host, path, method, None) +} +/// Missing ports mean the scheme's default, not any port. +pub fn rule_matches_port(r: &Rule, scheme: &str, host: &str, path: &str, method: &str, port: Option) -> bool { + let default = match scheme.to_ascii_lowercase().as_str() { + "http" => Some(80), "https" => Some(443), "ssh" => Some(22), _ => None, + }; + let host = host.trim_start_matches('[').trim_end_matches(']'); + safe_path(path) + && r.port.or(default) == port.or(default) + && r.scheme.eq_ignore_ascii_case(scheme) && r.hosts.iter().any(|p| { if let Some(s) = p.strip_prefix("*.") { host.to_ascii_lowercase() @@ -30,6 +43,20 @@ pub fn rule_matches(r: &Rule, scheme: &str, host: &str, path: &str, method: &str .as_ref() .is_none_or(|ms| ms.iter().any(|m| m.eq_ignore_ascii_case(method))) } +pub(crate) fn safe_path(path: &str) -> bool { + let lower = path.to_ascii_lowercase(); + !path.contains('\\') && !lower.contains("%2e") && !lower.contains("%2f") + && !lower.contains("%5c") && !path.split('/').any(|s| s == "." || s == "..") +} +fn local_host(host: &str) -> bool { + let host = host.strip_prefix("*.").unwrap_or(host); + host.eq_ignore_ascii_case("localhost") || host.to_ascii_lowercase().ends_with(".localhost") + || host.parse::().is_ok_and(|ip| match ip { + std::net::IpAddr::V4(ip) => ip.is_loopback() || ip.is_link_local(), + std::net::IpAddr::V6(ip) => ip.is_loopback() || ip.is_unicast_link_local() + || ip.to_ipv4_mapped().is_some_and(|v4| v4.is_loopback() || v4.is_link_local()), + }) +} #[derive(Clone, Serialize, Deserialize)] pub struct Field { #[serde(default)] @@ -126,7 +153,9 @@ pub(crate) fn validate(item: &Item) -> Result<()> { if !matches!( r.scheme.to_ascii_lowercase().as_str(), "http" | "https" | "ssh" - ) || r.path_prefixes.iter().any(|p| !p.starts_with('/')) + ) || r.port == Some(0) + || (r.port.is_none() && r.hosts.iter().any(|h| local_host(h))) + || r.path_prefixes.iter().any(|p| !p.starts_with('/') || !safe_path(p)) || r.methods.as_ref().is_some_and(|ms| { ms.iter().any(|m| { m.is_empty() || !m.bytes().all(|b| b.is_ascii_alphabetic() || b == b'-') @@ -187,9 +216,14 @@ pub struct ItemVersion { pub created: i64, pub config: Item, } +/// Plain entry is bootstrap-only. Verified entry decrypts the exact bound envelope here. +pub enum FieldValue<'a> { + Plain(&'a str), + Encrypted { key: &'a super::entry::EntryKey, envelope: &'a super::entry::Envelope }, +} /// A secret-entry value with optional replacement metadata. Debug never includes the value. pub struct FieldInput<'a> { - pub value: &'a str, + pub value: FieldValue<'a>, pub field_type: Option, pub key_type: Option, } @@ -202,13 +236,17 @@ impl std::fmt::Debug for FieldInput<'_> { } } impl Cred { - /// Trusted host mutation. The route layer must verify a passkey before this call. - pub fn create_item(&self, item: Item, caller: &Caller, approver: &str) -> Result { + /// Create an item only with an exact proof or a transaction-checked bootstrap value. + pub fn create_item(&self, item: Item, caller: &Caller, proof: impl Into) -> Result { let mut s = self.access()?; let tx = s.db.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; - let item = insert_new(&tx, item, caller, Some(approver))?; + validate(&item)?; + let binding = super::webauthn::Binding::mutation(super::webauthn::Mutation::CreateItem, &item)?; + let approver = proof.into().check(&tx, &binding)?; + let item = insert_new(&tx, item, caller, approver.as_deref())?; tx.commit()?; + s.refresh_rules()?; Ok(item) } pub fn item_get(&self, id: &str) -> Result { @@ -242,18 +280,18 @@ impl Cred { field: &str, value: &str, caller: &Caller, - approver: &str, + proof: impl Into, ) -> Result<()> { self.set_field_input( item, field, &FieldInput { - value, + value: FieldValue::Plain(value), field_type: None, key_type: None, }, caller, - approver, + proof, ) } pub fn set_field_input( @@ -262,12 +300,28 @@ impl Cred { field: &str, input: &FieldInput<'_>, caller: &Caller, - approver: &str, + proof: impl Into, ) -> Result<()> { - let value = input.value; let mut s = self.access()?; let key = s.master.clone(); - let tx = s.db.transaction()?; + let tx = s.db.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; + let proof = proof.into(); + if matches!(&proof, super::webauthn::Proof::Verified(_)) && matches!(&input.value, FieldValue::Plain(_)) { + return Err(Error("binding_mismatch")); + } + let hash = match &input.value { FieldValue::Plain(_) => String::new(), FieldValue::Encrypted { envelope, .. } => envelope.sha256() }; + let approver = proof.check(&tx, &super::webauthn::Binding::SecretEntry { + item: item.into(), field: field.into(), ciphertext_sha256: hash, + field_type: input.field_type.clone(), key_type: input.key_type.clone(), + })?; + let decrypted; + let value = match &input.value { + FieldValue::Plain(value) => *value, + FieldValue::Encrypted { key, envelope } => { + decrypted = zeroize::Zeroizing::new(key.decrypt(envelope).map_err(|_| Error("secret_envelope"))?); + std::str::from_utf8(&decrypted).map_err(|_| Error("field_invalid"))? + }, + }; let mut config = load(&tx, item)?; let index = config .fields @@ -305,8 +359,9 @@ impl Cred { .checked_add(1) .ok_or(Error("version_exhausted"))?; save(&tx, &config)?; - super::audit::record(&tx, "field.set", caller, Some(item), Some(approver))?; + super::audit::record(&tx, "field.set", caller, Some(item), approver.as_deref())?; tx.commit()?; + s.refresh_rules()?; Ok(()) } pub(crate) fn credential(&self, item: &Item, secrets: bool) -> Result { diff --git a/host/src/cred/schema.rs b/host/src/cred/schema.rs index 9dd0a4b..bdd8090 100644 --- a/host/src/cred/schema.rs +++ b/host/src/cred/schema.rs @@ -1,12 +1,15 @@ //! Fresh credentials schema. No v2 migrations or vault lifecycle. pub(crate) const DDL: &str = " PRAGMA journal_mode=WAL; PRAGMA synchronous=FULL; PRAGMA foreign_keys=ON; +CREATE TABLE IF NOT EXISTS meta(key TEXT PRIMARY KEY, value BLOB NOT NULL); +CREATE TABLE IF NOT EXISTS passkey_credentials(id TEXT PRIMARY KEY, label TEXT NOT NULL, credential TEXT NOT NULL); CREATE TABLE IF NOT EXISTS items(id TEXT PRIMARY KEY, name TEXT UNIQUE NOT NULL, config TEXT NOT NULL); CREATE TABLE IF NOT EXISTS fields(item TEXT NOT NULL REFERENCES items(id) ON DELETE CASCADE, id TEXT NOT NULL, ciphertext BLOB NOT NULL, PRIMARY KEY(item,id)); CREATE TABLE IF NOT EXISTS versions(item TEXT NOT NULL, created INTEGER NOT NULL, config TEXT NOT NULL); -CREATE TABLE IF NOT EXISTS grants(id TEXT PRIMARY KEY, items TEXT NOT NULL, subject TEXT NOT NULL, exp INTEGER, max_uses INTEGER, uses INTEGER NOT NULL DEFAULT 0, revoked INTEGER NOT NULL DEFAULT 0, validator TEXT, note TEXT); -CREATE TABLE IF NOT EXISTS requests(id TEXT PRIMARY KEY, subject TEXT, key TEXT NOT NULL, payload TEXT NOT NULL, state TEXT NOT NULL, expires INTEGER NOT NULL, pid INTEGER NOT NULL, program TEXT NOT NULL, decision TEXT, approver TEXT, grant_id TEXT); +CREATE TABLE IF NOT EXISTS grants(id TEXT PRIMARY KEY, items TEXT NOT NULL, subject TEXT NOT NULL, exp INTEGER, max_uses INTEGER, uses INTEGER NOT NULL DEFAULT 0, revoked INTEGER NOT NULL DEFAULT 0, validator TEXT, note TEXT, revoked_at INTEGER); +CREATE TABLE IF NOT EXISTS requests(id TEXT PRIMARY KEY, subject TEXT, key TEXT NOT NULL, payload TEXT NOT NULL, state TEXT NOT NULL, expires INTEGER NOT NULL, pid INTEGER NOT NULL, program TEXT NOT NULL, decision TEXT, approver TEXT, grant_id TEXT, decided_at INTEGER); CREATE TABLE IF NOT EXISTS audit(id INTEGER PRIMARY KEY, time INTEGER NOT NULL, event TEXT NOT NULL, pid INTEGER NOT NULL, program TEXT NOT NULL, conversation TEXT, item TEXT, approver TEXT, payload_sha256 TEXT); +CREATE INDEX IF NOT EXISTS grant_live ON grants(revoked,exp); CREATE INDEX IF NOT EXISTS request_keys ON requests(subject,key); CREATE INDEX IF NOT EXISTS request_expiry ON requests(state,expires); "; diff --git a/host/src/cred/types.rs b/host/src/cred/types.rs index 8cae2af..eaed01b 100644 --- a/host/src/cred/types.rs +++ b/host/src/cred/types.rs @@ -1,7 +1,11 @@ //! Caller identity and mandatory field metadata. Reject mismatched key algorithms. use super::error::{Error, Result}; use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, Default, Serialize, Deserialize)] +/// The host builds identity from the process table, never from a request body. +/// ```compile_fail +/// let _: sausage::cred::Caller = serde_json::from_str("{}").unwrap(); +/// ``` +#[derive(Clone, Debug, Default, Serialize)] pub struct Caller { pub program: String, pub pid: u32, diff --git a/host/src/cred/webauthn.rs b/host/src/cred/webauthn.rs index f40417f..ba01583 100644 --- a/host/src/cred/webauthn.rs +++ b/host/src/cred/webauthn.rs @@ -1,246 +1,176 @@ -//! Passkey enrollment and single-use assertions for host-owned bindings. -//! The caller supplies cred.sqlite and serializes access to this manager. -//! Browser responses and challenges use WebAuthn JSON. Enrollment assertions -//! must bind the exact new label. Neither decision nor secret-entry assertions -//! authorize enrollment. Without passkeys, the host is unlocked and permits -//! first registration without a gate. Restart drops all pending challenges. +//! Passkey assertions produce private, single-use proofs for exact host-owned bindings. +//! Bootstrap proofs remain valid only while the decision transaction finds no passkeys. +//! The caller serializes access to this manager and supplies the credentials database. use anyhow::{Result, bail}; use rusqlite::{Connection, params}; use serde::{Deserialize, Serialize}; -use std::{ - collections::HashMap, - time::{Duration, Instant}, -}; +use std::{collections::HashMap, time::{Duration, Instant}}; use webauthn_rs::prelude::*; +use super::{requests::Overrides, types::FieldType}; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all="snake_case")] +pub enum Decision { Approve, Deny } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all="snake_case")] +pub enum Mutation { CreateItem, GrantCreate, RevokeSubjects, ResolveStale } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(tag = "type")] +#[serde(tag="type", deny_unknown_fields)] pub enum Binding { - Decision { - request_id: String, - decision: String, - overrides: serde_json::Value, - }, - SecretEntry { - item: String, - field: String, - ciphertext_sha256: String, - }, - Enrollment { - label: String, - }, + Decision { request_id:String, decision:Decision, overrides:Overrides, payload_sha256:String }, + SecretEntry { item:String, field:String, ciphertext_sha256:String, field_type:Option, key_type:Option }, + Mutation { action:Mutation, parameters_sha256:String }, + Enrollment { label:String }, } - -#[derive(Serialize, Deserialize)] -pub struct Gate { - pub id: String, - pub response: PublicKeyCredential, +impl Binding { + pub fn mutation(action:Mutation, parameters:&impl Serialize) -> super::Result { + Ok(Self::Mutation { action, parameters_sha256:digest(&serde_json::to_vec(parameters)?) }) + } +} +pub(crate) fn digest(bytes:&[u8]) -> String { + use sha2::{Digest, Sha256}; + hex::encode(Sha256::digest(bytes)) +} +/// Only successful WebAuthn verification constructs this value. It cannot be cloned. +pub struct Verified { credential:CredentialID, binding:Binding } +impl Verified { + pub fn credential(&self) -> &CredentialID { &self.credential } + pub fn binding(&self) -> &Binding { &self.binding } } - -#[derive(Serialize, Deserialize)] -pub struct Challenge { - pub id: String, - pub options: T, +/// The constructor checks the registry. Every mutation checks it again in its transaction. +#[derive(Clone, Copy)] +pub struct Unlocked(()); +pub enum Proof { Verified(Verified), Unlocked(Unlocked) } +impl From for Proof { fn from(v:Verified) -> Self { Self::Verified(v) } } +impl From for Proof { fn from(v:Unlocked) -> Self { Self::Unlocked(v) } } +impl Proof { + pub(crate) fn check(self, db:&Connection, expected:&Binding) -> super::Result> { + match self { + Self::Unlocked(_) => { + let unlocked:bool = db.query_row("SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)",[],|r|r.get(0))?; + if !unlocked { return Err(super::Error("assertion_required")); } + Ok(None) + }, + Self::Verified(v) => { + if &v.binding != expected { return Err(super::Error("binding_mismatch")); } + let id = serde_json::to_string(&v.credential)?; + let registered:bool = db.query_row("SELECT EXISTS(SELECT 1 FROM passkey_credentials WHERE id=?)",[&id],|r|r.get(0))?; + if !registered { return Err(super::Error("assertion_required")); } + Ok(Some(id)) + }, + } + } } - -struct Pending { - deadline: Instant, - value: T, +impl super::Cred { + pub fn unlocked(&self) -> super::Result { + let s = self.access()?; + let unlocked:bool = s.db.query_row("SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)",[],|r|r.get(0))?; + if !unlocked { return Err(super::Error("assertion_required")); } + Ok(Unlocked(())) + } } - +#[derive(Serialize, Deserialize)] +pub struct Gate { pub id:String, pub response:PublicKeyCredential } +#[derive(Serialize, Deserialize)] +pub struct Challenge { pub id:String, pub options:T } +struct Pending { deadline:Instant, value:T } pub struct Passkeys<'a> { - db: &'a Connection, - webauthn: Webauthn, - registrations: HashMap>, - assertions: HashMap>, + db:&'a Connection, webauthn:Webauthn, + registrations:HashMap>, + assertions:HashMap>, } - impl<'a> Passkeys<'a> { - pub fn new(db: &'a Connection, rp_id: &str, origin: &str) -> Result { + pub fn new(db:&'a Connection,rp_id:&str,origin:&str) -> Result { let origin = Url::parse(origin)?; - let webauthn = WebauthnBuilder::new(rp_id, &origin)?.build()?; - db.execute_batch( - "CREATE TABLE IF NOT EXISTS passkey_credentials ( - id TEXT PRIMARY KEY, label TEXT NOT NULL, credential TEXT NOT NULL)", - )?; - Ok(Self { - db, - webauthn, - registrations: HashMap::new(), - assertions: HashMap::new(), - }) + let webauthn = WebauthnBuilder::new(rp_id,&origin)?.build()?; + db.execute_batch("CREATE TABLE IF NOT EXISTS passkey_credentials(id TEXT PRIMARY KEY,label TEXT NOT NULL,credential TEXT NOT NULL)")?; + Ok(Self { db, webauthn, registrations:HashMap::new(), assertions:HashMap::new() }) } - /// Database errors leave the manager locked. pub fn is_unlocked(&self) -> bool { - self.db - .query_row( - "SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)", - [], - |row| row.get(0), - ) - .unwrap_or(false) + self.db.query_row("SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)",[],|r|r.get(0)).unwrap_or(false) } - fn credentials(&self) -> Result> { - let mut stmt = self - .db - .prepare("SELECT credential FROM passkey_credentials")?; - let rows = stmt.query_map([], |row| row.get::<_, String>(0))?; - rows.map(|row| Ok(serde_json::from_str(&row?)?)).collect() + let mut q = self.db.prepare("SELECT credential FROM passkey_credentials")?; + q.query_map([],|r|r.get::<_,String>(0))?.map(|r|Ok(serde_json::from_str(&r?)?)).collect() } - - pub fn start_registration( - &mut self, - label: String, - gate: Option, - ) -> Result> { + pub fn start_registration(&mut self,label:String,gate:Option) -> Result> { let gated = gate.is_some(); match gate { None if !self.is_unlocked() => bail!("enrollment assertion required"), - None => {} - Some(Gate { id, response }) => { - let (_, binding) = self.finish_assertion(&id, response)?; - if binding - != (Binding::Enrollment { - label: label.clone(), - }) - { - bail!("invalid enrollment gate"); - } - } - } - let exclude = self - .credentials()? - .iter() - .map(|p| p.cred_id().clone()) - .collect(); - let (options, state) = self.webauthn.start_passkey_registration( - Uuid::new_v4(), - &label, - &label, - Some(exclude), - )?; - self.registrations - .retain(|_, p| p.deadline > Instant::now()); - let id = Uuid::new_v4().to_string(); - self.registrations.insert( - id.clone(), - Pending { - deadline: Instant::now() + Duration::from_secs(300), - value: (label, gated, state), + None => {}, + Some(Gate { id,response }) => { + let proof = self.finish_assertion(&id,response)?; + if proof.binding != (Binding::Enrollment { label:label.clone() }) { bail!("invalid enrollment gate"); } }, - ); - Ok(Challenge { id, options }) - } - - pub fn finish_registration( - &mut self, - id: &str, - response: RegisterPublicKeyCredential, - ) -> Result { - let (label, gated, state) = take(&mut self.registrations, id)?; - if !gated && !self.is_unlocked() { - bail!("enrollment assertion required"); } - let credential = self - .webauthn - .finish_passkey_registration(&response, &state)?; - self.db.execute( - "INSERT INTO passkey_credentials (id, label, credential) VALUES (?1, ?2, ?3)", - params![ - serde_json::to_string(credential.cred_id())?, - label, - serde_json::to_string(&credential)? - ], - )?; + let exclude = self.credentials()?.iter().map(|p|p.cred_id().clone()).collect(); + let (options,state) = self.webauthn.start_passkey_registration(Uuid::new_v4(),&label,&label,Some(exclude))?; + trim(&mut self.registrations); + let id = Uuid::new_v4().to_string(); + self.registrations.insert(id.clone(),Pending { deadline:Instant::now()+Duration::from_secs(300), value:(label,gated,state) }); + Ok(Challenge { id,options }) + } + pub fn finish_registration(&mut self,id:&str,response:RegisterPublicKeyCredential) -> Result { + let unlocked = self.is_unlocked(); + let (label,gated,state) = pending(&mut self.registrations,id)?; + if !*gated && !unlocked { bail!("enrollment assertion required"); } + let credential = self.webauthn.finish_passkey_registration(&response,state)?; + self.db.execute("INSERT INTO passkey_credentials(id,label,credential) VALUES(?1,?2,?3)",params![serde_json::to_string(credential.cred_id())?,label,serde_json::to_string(&credential)?])?; + self.registrations.remove(id); Ok(credential) } - - pub fn start_assertion( - &mut self, - binding: Binding, - ) -> Result> { - let (options, state) = self - .webauthn - .start_passkey_authentication(&self.credentials()?)?; - self.assertions.retain(|_, p| p.deadline > Instant::now()); + pub fn start_assertion(&mut self,binding:Binding) -> Result> { + let (options,state) = self.webauthn.start_passkey_authentication(&self.credentials()?)?; + trim(&mut self.assertions); let id = Uuid::new_v4().to_string(); - self.assertions.insert( - id.clone(), - Pending { - deadline: Instant::now() + Duration::from_secs(300), - value: (binding, state), - }, - ); - Ok(Challenge { id, options }) + self.assertions.insert(id.clone(),Pending { deadline:Instant::now()+Duration::from_secs(300), value:(binding,state) }); + Ok(Challenge { id,options }) } - - pub fn finish_assertion( - &mut self, - id: &str, - response: PublicKeyCredential, - ) -> Result<(CredentialID, Binding)> { - let (binding, state) = take(&mut self.assertions, id)?; - let result = self - .webauthn - .finish_passkey_authentication(&response, &state)?; + pub fn finish_assertion(&mut self,id:&str,response:PublicKeyCredential) -> Result { + let (binding,state) = pending(&mut self.assertions,id)?; + let binding = binding.clone(); + let result = self.webauthn.finish_passkey_authentication(&response,state)?; let mut credentials = self.credentials()?; - let credential = credentials - .iter_mut() - .find(|p| p.cred_id() == result.cred_id()) - .ok_or_else(|| anyhow::anyhow!("unregistered passkey"))?; - // Check the latest stored counter too. Another outstanding assertion may - // contain an older snapshot of this credential. + let credential = credentials.iter_mut().find(|p|p.cred_id()==result.cred_id()).ok_or_else(||anyhow::anyhow!("unregistered passkey"))?; let stored = serde_json::to_value(&*credential)?; - let counter = stored["cred"]["counter"] - .as_u64() - .ok_or_else(|| anyhow::anyhow!("invalid stored passkey counter"))?; - if (counter > 0 || result.counter() > 0) && u64::from(result.counter()) <= counter { - bail!("passkey counter did not increase"); - } + let counter = stored["cred"]["counter"].as_u64().ok_or_else(||anyhow::anyhow!("invalid stored passkey counter"))?; + if (counter>0 || result.counter()>0) && u64::from(result.counter())<=counter { bail!("passkey counter did not increase"); } credential.update_credential(&result); - self.db.execute( - "UPDATE passkey_credentials SET credential = ?1 WHERE id = ?2", - params![ - serde_json::to_string(credential)?, - serde_json::to_string(result.cred_id())? - ], - )?; - Ok((result.cred_id().clone(), binding)) + self.db.execute("UPDATE passkey_credentials SET credential=?1 WHERE id=?2",params![serde_json::to_string(credential)?,serde_json::to_string(result.cred_id())?])?; + self.assertions.remove(id); + Ok(Verified { credential:result.cred_id().clone(),binding }) } } - -fn take(map: &mut HashMap>, id: &str) -> Result { - let pending = map - .remove(id) - .ok_or_else(|| anyhow::anyhow!("unknown or consumed challenge"))?; - if pending.deadline <= Instant::now() { - bail!("expired challenge"); +fn pending<'a,T>(map:&'a mut HashMap>,id:&str) -> Result<&'a T> { + let expired = map.get(id).ok_or_else(||anyhow::anyhow!("unknown or consumed challenge"))?.deadline<=Instant::now(); + if expired { map.remove(id); bail!("expired challenge"); } + Ok(&map.get(id).expect("checked challenge").value) +} +fn trim(map:&mut HashMap>) { + map.retain(|_,p|p.deadline>Instant::now()); + if map.len()>=32 { + let id = map.iter().min_by_key(|(_,p)|p.deadline).map(|(id,_)|id.clone()).expect("full challenge map"); + map.remove(&id); } - Ok(pending.value) } - #[cfg(test)] mod tests { use super::*; - #[test] fn expired_assertion() -> Result<()> { - use webauthn_authenticator_rs::{WebauthnAuthenticator, softpasskey::SoftPasskey}; + use webauthn_authenticator_rs::{WebauthnAuthenticator,softpasskey::SoftPasskey}; let db = Connection::open_in_memory()?; - let mut host = Passkeys::new(&db, "localhost", "http://localhost:8000")?; - let start = host.start_registration("test".into(), None)?; + let mut host = Passkeys::new(&db,"localhost","http://localhost:8000")?; + let start = host.start_registration("test".into(),None)?; let mut auth = WebauthnAuthenticator::new(SoftPasskey::new(true)); let origin = Url::parse("http://localhost:8000")?; - let response = auth.do_registration(origin.clone(), start.options)?; - host.finish_registration(&start.id, response)?; - let start = host.start_assertion(Binding::Enrollment { - label: "next".into(), - })?; - let response = auth.do_authentication(origin, start.options)?; - host.assertions.get_mut(&start.id).unwrap().deadline = Instant::now(); - assert!(host.finish_assertion(&start.id, response).is_err()); + let response = auth.do_registration(origin.clone(),start.options)?; + host.finish_registration(&start.id,response)?; + let start = host.start_assertion(Binding::Enrollment { label:"next".into() })?; + let response = auth.do_authentication(origin,start.options)?; + host.assertions.get_mut(&start.id).unwrap().deadline=Instant::now(); + assert!(host.finish_assertion(&start.id,response).is_err()); assert!(!host.assertions.contains_key(&start.id)); Ok(()) } diff --git a/host/tests/cred.rs b/host/tests/cred.rs index 450337f..1a048eb 100644 --- a/host/tests/cred.rs +++ b/host/tests/cred.rs @@ -21,6 +21,7 @@ fn item(free_use: bool) -> Item { version: 0, free_use, rules: vec![Rule { + port: None, scheme: "https".into(), hosts: vec!["api.example".into()], path_prefixes: vec!["/".into()], @@ -74,7 +75,7 @@ fn inject_selection_idempotency_and_subtree() { c.inject(parts("api.example"), &root, &Fake).unwrap(), Outcome::Forward(_) )); - let i = c.create_item(item(false), &root, "passkey").unwrap(); + let i = c.create_item(item(false), &root, c.unlocked().unwrap()).unwrap(); let first = match c.inject(parts("api.example"), &root, &Fake).unwrap() { Outcome::Denied { item, request } => { assert_eq!(item, "token"); @@ -88,9 +89,9 @@ fn inject_selection_idempotency_and_subtree() { }; assert_eq!(first, second); assert_eq!(c.request_list().unwrap().len(), 1); - c.set_field(&i.id, &i.fields[0].field_id, "opaque", &root, "passkey") + c.set_field(&i.id, &i.fields[0].field_id, "opaque", &root, c.unlocked().unwrap()) .unwrap(); - c.approve(&first, "allow", Overrides::default(), Some("passkey")) + c.approve(&first, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap(); let child = Caller { program: "/bin/tool.wasm".into(), @@ -108,7 +109,7 @@ fn inject_selection_idempotency_and_subtree() { )); let mut other = item(true); other.name = "other".into(); - c.create_item(other, &root, "passkey").unwrap(); + c.create_item(other, &root, c.unlocked().unwrap()).unwrap(); assert_eq!( c.inject(parts("api.example"), &root, &Fake) .err() @@ -132,9 +133,9 @@ fn free_use_validators_transform_recheck_and_redaction() { let mut config = item(true); config.transform_js = source.into(); config.validate_js = validator.map(Into::into); - let i = c.create_item(config, &caller, "passkey").unwrap(); + let i = c.create_item(config, &caller, c.unlocked().unwrap()).unwrap(); let secret = "SECRET_SENTINEL_19"; - c.set_field(&i.id, &i.fields[0].field_id, secret, &caller, "passkey") + c.set_field(&i.id, &i.fields[0].field_id, secret, &caller, c.unlocked().unwrap()) .unwrap(); let result = c.inject(parts("api.example"), &caller, &Fake); if let Some(expected) = expected { @@ -174,8 +175,8 @@ fn atomic_budget_and_decision_notification() { let dir = tempfile::tempdir().unwrap(); let c = std::sync::Arc::new(Cred::open(dir.path()).unwrap()); let caller = caller("root"); - let i = c.create_item(item(false), &caller, "passkey").unwrap(); - c.set_field(&i.id, &i.fields[0].field_id, "opaque", &caller, "passkey") + let i = c.create_item(item(false), &caller, c.unlocked().unwrap()).unwrap(); + c.set_field(&i.id, &i.fields[0].field_id, "opaque", &caller, c.unlocked().unwrap()) .unwrap(); c.grant_create( Grant { @@ -190,7 +191,7 @@ fn atomic_budget_and_decision_notification() { note: None, }, &caller, - Some("passkey"), + c.unlocked().unwrap(), ) .unwrap(); let handles: Vec<_> = (0..2) @@ -214,10 +215,10 @@ fn atomic_budget_and_decision_notification() { ); let id = c.request_list().unwrap()[0].id.clone(); let mut receiver = c.subscribe(); - c.deny(&id, "no", Some("passkey")).unwrap(); + c.deny(&id, sausage::cred::webauthn::Decision::Deny, c.unlocked().unwrap()).unwrap(); assert_eq!(receiver.try_recv().unwrap(), id); assert_eq!( - c.deny(&id, "again", Some("passkey")).unwrap_err().0, + c.deny(&id, sausage::cred::webauthn::Decision::Deny, c.unlocked().unwrap()).unwrap_err().0, "already_decided" ); } @@ -229,13 +230,13 @@ fn key_and_secret_persist() { let caller = caller("root"); let mut config = item(true); config.transform_js = "inject".into(); - let i = c.create_item(config, &caller, "passkey").unwrap(); + let i = c.create_item(config, &caller, c.unlocked().unwrap()).unwrap(); c.set_field( &i.id, &i.fields[0].field_id, "persistent", &caller, - "passkey", + c.unlocked().unwrap(), ) .unwrap(); drop(c); diff --git a/host/tests/cred_authorization.rs b/host/tests/cred_authorization.rs new file mode 100644 index 0000000..f4f2c4e --- /dev/null +++ b/host/tests/cred_authorization.rs @@ -0,0 +1,36 @@ +//! Bootstrap proofs cannot survive registration. Typed overrides reject misspelled limits. +use sausage::cred::{*, items::{Item,Field}, requests::{GrantRequest,Overrides}, webauthn::{Decision,Unlocked}}; +fn fixture() -> (tempfile::TempDir,Cred,Caller,Item,String,Unlocked) { + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let proof = c.unlocked().unwrap(); + let caller = Caller { program:"/bin/test.wasm".into(),pid:1,conversations:vec!["root".into()] }; + let item = c.create_item(Item { id:String::new(),name:"test".into(),version:0,free_use:false,rules:vec![],validate_js:None,transform_js:String::new(),fields:vec![Field { field_id:String::new(),name:"secret".into(),public:false,value:None,needs_value:true,field_type:types::FieldType::Text,key_type:None }] },&caller,proof).unwrap(); + let id = c.file_request(&caller,"request",GrantRequest { items:vec![item.id.clone()],duration_secs:None,max_uses:None,validator:None }).unwrap(); + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + db.execute("INSERT INTO passkey_credentials VALUES('synthetic','test','{}')",[]).unwrap(); + (dir,c,caller,item,id,proof) +} +#[test] +fn registered_passkey_refuses_unlocked_approval() { + let (_dir,c,_caller,_item,id,proof) = fixture(); + assert!(c.approve(&id,Decision::Approve,Overrides::default(),proof).is_err()); + assert_eq!(c.request_list().unwrap()[0].state,"pending"); + assert!(c.unlocked().is_err()); +} +#[test] +fn registered_passkey_refuses_unlocked_denial() { + let (_dir,c,_caller,_item,id,proof) = fixture(); + assert!(c.deny(&id,Decision::Deny,proof).is_err()); +} +#[test] +fn registered_passkey_refuses_direct_mutations() { + let (_dir,c,caller,item,_id,proof) = fixture(); + assert!(c.set_field(&item.id,&item.fields[0].field_id,"synthetic",&caller,proof).is_err()); + assert!(c.create_item(Item { name:"another".into(),..item },&caller,proof).is_err()); + assert!(c.revoke_subjects(&caller.conversations,&caller,proof).is_err()); +} +#[test] +fn overrides_reject_unknown_fields() { + assert!(serde_json::from_value::(serde_json::json!({"max_use":1})).is_err()); +} diff --git a/host/tests/cred_challenges.rs b/host/tests/cred_challenges.rs new file mode 100644 index 0000000..dca4358 --- /dev/null +++ b/host/tests/cred_challenges.rs @@ -0,0 +1,26 @@ +//! Invalid responses cannot cancel valid challenges. Pending ceremonies have a fixed bound. +use sausage::cred::webauthn::{Binding, Passkeys}; +use webauthn_authenticator_rs::{WebauthnAuthenticator, softpasskey::SoftPasskey}; +use webauthn_rs::prelude::*; +#[test] +fn failed_response_preserves_challenge_and_oldest_challenge_is_evicted() -> anyhow::Result<()> { + let db = rusqlite::Connection::open_in_memory()?; + let origin = Url::parse("http://localhost:8000")?; + let mut host = Passkeys::new(&db,"localhost",origin.as_str())?; + let mut auth = WebauthnAuthenticator::new(SoftPasskey::new(true)); + let registration = host.start_registration("test".into(),None)?; + let response = auth.do_registration(origin.clone(),registration.options)?; + host.finish_registration(®istration.id,response)?; + let binding = Binding::Enrollment { label:"next".into() }; + let valid = host.start_assertion(binding.clone())?; + let wrong = host.start_assertion(binding.clone())?; + let invalid_response = auth.do_authentication(origin.clone(),wrong.options)?; + assert!(host.finish_assertion(&valid.id,invalid_response).is_err()); + let response = auth.do_authentication(origin.clone(),valid.options)?; + host.finish_assertion(&valid.id,response)?; + let oldest = host.start_assertion(binding.clone())?; + for _ in 0..32 { host.start_assertion(binding.clone())?; } + let response = auth.do_authentication(origin,oldest.options)?; + assert!(host.finish_assertion(&oldest.id,response).is_err()); + Ok(()) +} diff --git a/host/tests/cred_core.rs b/host/tests/cred_core.rs index a5d09a4..4c3115e 100644 --- a/host/tests/cred_core.rs +++ b/host/tests/cred_core.rs @@ -34,7 +34,7 @@ fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { }], }, &caller, - "pk", + c.unlocked().unwrap(), ) .unwrap(); (dir, c, caller, i) @@ -96,7 +96,7 @@ fn rule_matching_table() { #[test] fn revisions_needs_value_and_rename_are_metadata_only() { let (_dir, c, caller, i) = fixture(); - c.set_field(&i.id, &i.fields[0].field_id, "opaque", &caller, "pk") + c.set_field(&i.id, &i.fields[0].field_id, "opaque", &caller, c.unlocked().unwrap()) .unwrap(); let old = c.item_get(&i.id).unwrap(); assert_eq!(old.version, 2); @@ -117,7 +117,7 @@ fn revisions_needs_value_and_rename_are_metadata_only() { ) .unwrap(); assert!(!c.edit_diff(&id).unwrap().discards_values); - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap(); let current = c.item_get(&i.id).unwrap(); assert_eq!(current.version, 3); @@ -139,10 +139,10 @@ fn stale_edits_leave_history_and_values_untouched() { }, ) .unwrap(); - c.set_field(&i.id, &i.fields[0].field_id, "opaque", &caller, "pk") + c.set_field(&i.id, &i.fields[0].field_id, "opaque", &caller, c.unlocked().unwrap()) .unwrap(); assert_eq!( - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap_err() .0, "stale" @@ -166,18 +166,20 @@ fn key_conflict_renewal_and_expiry() { c.file_request(&caller, "key", other).unwrap_err().0, "key_conflict" ); - c.deny(&id, "no", Some("pk")).unwrap(); + c.deny(&id, sausage::cred::webauthn::Decision::Deny, c.unlocked().unwrap()).unwrap(); + assert_eq!(c.file_request(&caller, "key", p.clone()).unwrap(), id); + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + db.execute("UPDATE requests SET expires=0 WHERE id=?", [&id]).unwrap(); let next = c.file_request(&caller, "key", p).unwrap(); assert_ne!(id, next); assert_eq!(c.request_decisions().unwrap().len(), 1); - let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); db.execute("UPDATE requests SET expires=0 WHERE id=?", [&next]) .unwrap(); let mut notification = c.subscribe(); assert_eq!(c.expire_requests().unwrap(), vec![next.clone()]); assert_eq!(notification.try_recv().unwrap(), next); assert_eq!( - c.approve(&next, "yes", Overrides::default(), Some("pk")) + c.approve(&next, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap_err() .0, "request_expired" @@ -188,7 +190,7 @@ fn key_conflict_renewal_and_expiry() { fn typed_values_and_secret_configuration_fail_without_writes() { let (_dir, c, caller, i) = fixture(); assert_eq!( - c.set_field(&i.id, &i.fields[0].field_id, "line\nbreak", &caller, "pk") + c.set_field(&i.id, &i.fields[0].field_id, "line\nbreak", &caller, c.unlocked().unwrap()) .unwrap_err() .0, "invalid_value" @@ -197,7 +199,7 @@ fn typed_values_and_secret_configuration_fail_without_writes() { let mut config = i.clone(); config.fields[0].value = Some("forbidden".into()); assert_eq!( - c.create_item(config, &caller, "pk").unwrap_err().0, + c.create_item(config, &caller, c.unlocked().unwrap()).unwrap_err().0, "secret_field" ); assert_eq!(c.item_list().unwrap().len(), 1); diff --git a/host/tests/cred_edits.rs b/host/tests/cred_edits.rs index ab8beeb..f9357d0 100644 --- a/host/tests/cred_edits.rs +++ b/host/tests/cred_edits.rs @@ -48,7 +48,7 @@ fn creation_key_generation_and_deletion_keep_secrets_out_of_history() { ) .unwrap(); assert!(c.item_list().unwrap().is_empty()); - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap(); let item = c.item_list().unwrap().remove(0); assert!(!item.fields[0].needs_value); @@ -69,7 +69,7 @@ fn creation_key_generation_and_deletion_keep_secrets_out_of_history() { }, ) .unwrap(); - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap(); assert!(c.item_list().unwrap().is_empty()); assert_eq!(c.item_versions(&item.id).unwrap().len(), 1); @@ -89,8 +89,8 @@ fn operation_order_name_conflicts_and_stale_resolution() { pid: 3, conversations: vec!["root".into()], }; - let item = c.create_item(config("first"), &caller, "pk").unwrap(); - c.create_item(config("taken"), &caller, "pk").unwrap(); + let item = c.create_item(config("first"), &caller, c.unlocked().unwrap()).unwrap(); + c.create_item(config("taken"), &caller, c.unlocked().unwrap()).unwrap(); let request = |change| OperationRequest { item: Some(item.id.clone()), base_version: Some(item.version), @@ -129,18 +129,18 @@ fn operation_order_name_conflicts_and_stale_resolution() { request(vec![Operation::SetFreeUse { enabled: true }]), ) .unwrap(); - c.approve(&other, "yes", Overrides::default(), Some("pk")) + c.approve(&other, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap(); assert!(c.edit_diff(&id).unwrap().stale); assert_eq!( - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap_err() .0, "stale" ); - c.resolve_stale(&id, 2).unwrap(); + c.resolve_stale(&id, 2, &caller, c.unlocked().unwrap()).unwrap(); assert!(!c.edit_diff(&id).unwrap().stale); - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap(); let current = c.item_get(&item.id).unwrap(); assert_eq!(current.name, "last"); @@ -167,13 +167,13 @@ fn field_removal_revert_and_public_visibility() { field_type: types::FieldType::Text, key_type: None, }); - let item = c.create_item(initial, &caller, "pk").unwrap(); + let item = c.create_item(initial, &caller, c.unlocked().unwrap()).unwrap(); c.set_field( &item.id, &item.fields[0].field_id, "SECRET_REMOVED", &caller, - "pk", + c.unlocked().unwrap(), ) .unwrap(); let current = c.item_get(&item.id).unwrap(); @@ -198,12 +198,12 @@ fn field_removal_revert_and_public_visibility() { ) .unwrap(); assert!(c.edit_diff(&id).unwrap().discards_values); - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap(); let id = c .file_revert_request(&caller, "revert", &item.id, 3, 2) .unwrap(); - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap(); let restored = c.item_get(&item.id).unwrap(); assert!(restored.fields[0].needs_value); @@ -253,14 +253,14 @@ fn decision_failure_rolls_back_every_write() { let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); db.execute_batch("CREATE TRIGGER fail_decision BEFORE UPDATE ON requests BEGIN SELECT RAISE(ABORT, 'forced'); END;").unwrap(); assert!( - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .is_err() ); assert!(c.item_list().unwrap().is_empty()); assert!(c.audit_list().unwrap().is_empty()); assert_eq!(c.request_list().unwrap()[0].state, "pending"); db.execute_batch("DROP TRIGGER fail_decision;").unwrap(); - c.approve(&id, "yes", Overrides::default(), Some("pk")) + c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) .unwrap(); assert_eq!(c.item_list().unwrap().len(), 1); } diff --git a/host/tests/cred_grants.rs b/host/tests/cred_grants.rs index b28d18a..b90a321 100644 --- a/host/tests/cred_grants.rs +++ b/host/tests/cred_grants.rs @@ -43,6 +43,7 @@ fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { version: 0, free_use: false, rules: vec![Rule { + port: None, scheme: "https".into(), hosts: vec!["api.test".into()], path_prefixes: vec!["/".into()], @@ -53,7 +54,7 @@ fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { fields: vec![], }, &caller, - "pk", + c.unlocked().unwrap(), ) .unwrap(); (dir, c, caller, i) @@ -88,9 +89,9 @@ fn program_grant_covers_service_and_agent_but_not_another_program() { ); c.approve( &request, - "allow", + sausage::cred::webauthn::Decision::Approve, sausage::cred::requests::Overrides::default(), - None, + c.unlocked().unwrap(), ) .unwrap(); let agent = Caller { @@ -122,7 +123,7 @@ fn program_grant_covers_service_and_agent_but_not_another_program() { #[test] fn expiry_boundary_revoke_and_exhaustion() { let (dir, c, caller, i) = fixture(); - let g = c.grant_create(grant(&i), &caller, Some("pk")).unwrap(); + let g = c.grant_create(grant(&i), &caller, c.unlocked().unwrap()).unwrap(); assert!(matches!( c.inject(parts(), &caller, &Fake).unwrap(), Outcome::Forward(_) @@ -135,7 +136,7 @@ fn expiry_boundary_revoke_and_exhaustion() { assert_eq!(c.grant_status(&g.id).unwrap().uses, 1); let mut unlimited = grant(&i); unlimited.max_uses = None; - let g = c.grant_create(unlimited, &caller, Some("pk")).unwrap(); + let g = c.grant_create(unlimited, &caller, c.unlocked().unwrap()).unwrap(); let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); db.execute("UPDATE grants SET exp=0 WHERE id=?", [&g.id]) .unwrap(); @@ -144,7 +145,7 @@ fn expiry_boundary_revoke_and_exhaustion() { Outcome::Denied { .. } )); assert_eq!(c.grant_status(&g.id).unwrap().uses, 0); - c.revoke_subjects(&caller.conversations, &caller, Some("pk")) + c.revoke_subjects(&caller.conversations, &caller, c.unlocked().unwrap()) .unwrap(); assert!(c.grant_list().unwrap().iter().all(|g| g.revoked)); } @@ -154,13 +155,13 @@ fn reject_bad_issuance_without_rows() { let mut g = grant(&i); g.max_uses = Some(0); assert_eq!( - c.grant_create(g, &caller, Some("pk")).unwrap_err().0, + c.grant_create(g, &caller, c.unlocked().unwrap()).unwrap_err().0, "invalid_uses" ); let mut g = grant(&i); g.subject = types::Subject::Conversation(String::new()); assert_eq!( - c.grant_create(g, &caller, Some("pk")).unwrap_err().0, + c.grant_create(g, &caller, c.unlocked().unwrap()).unwrap_err().0, "invalid_subject" ); assert!(c.grant_list().unwrap().is_empty()); @@ -171,7 +172,7 @@ fn preflight_spends_nothing_and_validator_denial_spends_one() { let (_dir, c, caller, i) = fixture(); let mut g = grant(&i); g.validator = Some("deny".into()); - let g = c.grant_create(g, &caller, Some("pk")).unwrap(); + let g = c.grant_create(g, &caller, c.unlocked().unwrap()).unwrap(); let mut p = parts(); p.headers .insert("bad", http::HeaderValue::from_bytes(&[0xff]).unwrap()); @@ -194,6 +195,6 @@ fn preflight_spends_nothing_and_validator_denial_spends_one() { audit .iter() .filter(|r| r.event == "grant.create") - .all(|r| r.approver.as_deref() == Some("pk")) + .all(|r| r.approver.is_none()) ); } diff --git a/host/tests/cred_policy.rs b/host/tests/cred_policy.rs new file mode 100644 index 0000000..38ed48c --- /dev/null +++ b/host/tests/cred_policy.rs @@ -0,0 +1,44 @@ +//! Approval policy regressions for explicit grant operations and denied request replay. +use sausage::cred::{*, edits::{Operation, OperationRequest}, grants::Grant, items::Item, requests::{GrantRequest, Overrides}}; +fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller { program:"/bin/test.wasm".into(), pid:1, conversations:vec!["root".into()] }; + let item = c.create_item(serde_json::from_value(serde_json::json!({"name":"test","rules":[],"validate_js":null,"transform_js":"","fields":[]})).unwrap(), &caller, "test").unwrap(); + (dir,c,caller,item) +} +fn grant(item: &Item) -> Grant { + Grant { id:String::new(), items:vec![item.id.clone()], subject:types::Subject::Conversation("root".into()), exp:None, max_uses:None, uses:0, revoked:false, validator:None, note:None } +} +fn operation(c: &Cred, caller: &Caller, key: &str, op: Operation) -> String { + c.file_operation_request(caller, key, OperationRequest { item:None, base_version:None, change:vec![op] }).unwrap() +} +#[test] +fn grant_operations_apply_overrides_defaults_and_replay_liveness() { + let (_dir,c,caller,item) = fixture(); + let op = Operation::GrantCreate { grant:grant(&item) }; + let id = operation(&c,&caller,"grant",op.clone()); + c.approve(&id,"allow",Overrides { duration_secs:Some(120), max_uses:Some(1), validator:Some("true".into()), unlimited:false },None).unwrap(); + let g = c.grant_list().unwrap().pop().unwrap(); + let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as i64; + assert!(g.exp.is_some_and(|e| (now+115..=now+120).contains(&e))); + assert_eq!(g.max_uses,Some(1)); + assert_eq!(g.validator.as_deref(),Some("true")); + let revoke = operation(&c,&caller,"revoke",Operation::GrantRevoke { target:g.id }); + assert!(c.approve(&revoke,"allow",Overrides { duration_secs:Some(1), ..Default::default() },None).is_err()); + c.approve(&revoke,"allow",Overrides::default(),None).unwrap(); + assert_ne!(operation(&c,&caller,"grant",op),id); + let id = operation(&c,&caller,"default",Operation::GrantCreate { grant:grant(&item) }); + c.approve(&id,"allow",Overrides::default(),None).unwrap(); + assert!(c.grant_list().unwrap().last().unwrap().exp.is_some_and(|e| (now+3595..=now+3605).contains(&e))); +} +#[test] +fn denial_replays_until_expiry_and_requester_duration_is_capped() { + let (_dir,c,caller,item) = fixture(); + let request = GrantRequest { items:vec![item.id], duration_secs:Some(86401), max_uses:None, validator:None }; + assert!(c.file_request(&caller,"too-long",request.clone()).is_err()); + let request = GrantRequest { duration_secs:None, ..request }; + let id = c.file_request(&caller,"denied",request.clone()).unwrap(); + c.deny(&id,"no",None).unwrap(); + assert_eq!(c.file_request(&caller,"denied",request).unwrap(),id); +} diff --git a/host/tests/cred_presentation.rs b/host/tests/cred_presentation.rs new file mode 100644 index 0000000..881d8a5 --- /dev/null +++ b/host/tests/cred_presentation.rs @@ -0,0 +1,16 @@ +//! Approval text exposes public policy and rejects deceptive display controls. +use sausage::cred::{edits::Operation, items::Item, summary::operation_summary}; +#[test] +fn summaries_show_public_values_rules_free_use_and_wildcard_risk() { + let item: Item = serde_json::from_value(serde_json::json!({"name":"test","free_use":true,"rules":[{"scheme":"https","hosts":["*.com","api.example"],"port":8443,"path_prefixes":["/"],"methods":null}],"validate_js":null,"transform_js":"","fields":[]})).unwrap(); + let text = operation_summary(&Operation::CreateItem { config:item }); + for part in ["without a grant","*.com","api.example","8443","wildcard"] { assert!(text.contains(part)); } + let text = operation_summary(&Operation::SetFieldValue { field:"public-id".into(), value:"public-value".into() }); + assert!(text.contains("public-id")); + assert!(text.contains("public-value")); +} +#[test] +fn summaries_remove_bidi_and_zero_width_controls() { + let text = operation_summary(&Operation::SetName { name:"a\u{202e}b\u{2066}c\u{200b}d\u{200d}e\u{feff}".into() }); + for c in ['\u{202e}','\u{2066}','\u{200b}','\u{200d}','\u{feff}'] { assert!(!text.contains(c)); } +} diff --git a/host/tests/cred_regressions.rs b/host/tests/cred_regressions.rs index adc8546..de824ad 100644 --- a/host/tests/cred_regressions.rs +++ b/host/tests/cred_regressions.rs @@ -35,6 +35,7 @@ fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { version: 0, free_use: false, rules: vec![Rule { + port: None, scheme: "https".into(), hosts: vec!["api.test".into()], path_prefixes: vec!["/".into()], @@ -64,7 +65,7 @@ fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { ], }, &caller, - "pk", + cred.unlocked().unwrap(), ) .unwrap(); (dir, cred, caller, item) @@ -93,7 +94,7 @@ fn grant(item: &Item) -> Grant { fn missing_values_and_wrong_master_spend_nothing() { let (dir, cred, caller, item) = fixture(); let grant = cred - .grant_create(grant(&item), &caller, Some("pk")) + .grant_create(grant(&item), &caller, cred.unlocked().unwrap()) .unwrap(); assert_eq!( cred.inject(parts(), &caller, &Fake).err().unwrap().0, @@ -101,23 +102,21 @@ fn missing_values_and_wrong_master_spend_nothing() { ); assert_eq!(cred.grant_status(&grant.id).unwrap().uses, 0); for field in &item.fields { - cred.set_field(&item.id, &field.field_id, "opaque", &caller, "pk") + cred.set_field(&item.id, &field.field_id, "opaque", &caller, cred.unlocked().unwrap()) .unwrap(); } drop(cred); std::fs::write(dir.path().join("cred.key"), [7u8; 32]).unwrap(); - let cred = Cred::open(dir.path()).unwrap(); - assert_eq!( - cred.inject(parts(), &caller, &Fake).err().unwrap().0, - "seal" - ); - assert_eq!(cred.grant_status(&grant.id).unwrap().uses, 0); + assert!(Cred::open(dir.path()).is_err()); + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + let uses: i64 = db.query_row("SELECT uses FROM grants WHERE id=?", [&grant.id], |r| r.get(0)).unwrap(); + assert_eq!(uses, 0); } #[test] fn field_name_swaps_preserve_ciphertexts_and_failed_edits_roll_back() { let (dir, cred, caller, item) = fixture(); for field in &item.fields { - cred.set_field(&item.id, &field.field_id, "opaque", &caller, "pk") + cred.set_field(&item.id, &field.field_id, "opaque", &caller, cred.unlocked().unwrap()) .unwrap(); } let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); @@ -146,7 +145,7 @@ fn field_name_swaps_preserve_ciphertexts_and_failed_edits_roll_back() { }, ) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); assert!(cipher() == before); let current = cred.item_get(&item.id).unwrap(); @@ -167,7 +166,7 @@ fn field_name_swaps_preserve_ciphertexts_and_failed_edits_roll_back() { let audit = cred.audit_list().unwrap().len(); db.execute_batch("CREATE TRIGGER fail_decision BEFORE UPDATE ON requests BEGIN SELECT RAISE(ABORT,'forced'); END;").unwrap(); assert!( - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .is_err() ); assert!(cipher() == before); @@ -179,7 +178,7 @@ fn field_name_swaps_preserve_ciphertexts_and_failed_edits_roll_back() { fn deleted_item_revert_preserves_identity_but_never_restores_secrets() { let (_dir, cred, caller, item) = fixture(); for field in &item.fields { - cred.set_field(&item.id, &field.field_id, "opaque", &caller, "pk") + cred.set_field(&item.id, &field.field_id, "opaque", &caller, cred.unlocked().unwrap()) .unwrap(); } let current = cred.item_get(&item.id).unwrap(); @@ -193,7 +192,7 @@ fn deleted_item_revert_preserves_identity_but_never_restores_secrets() { }, ) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); let id = cred .file_revert_request( @@ -204,7 +203,7 @@ fn deleted_item_revert_preserves_identity_but_never_restores_secrets() { current.version, ) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); let restored = cred.item_get(&item.id).unwrap(); assert_eq!(restored.id, item.id); @@ -221,13 +220,13 @@ fn deleted_item_revert_preserves_identity_but_never_restores_secrets() { fn secret_entry_keeps_oauth_cardinality_and_rolls_back_ciphertext() { let (dir, cred, caller, item) = fixture(); let input = FieldInput { - value: "opaque", + value: sausage::cred::items::FieldValue::Plain("opaque"), field_type: Some(types::FieldType::Oauth2RefreshToken), key_type: None, }; - cred.set_field_input(&item.id, &item.fields[0].field_id, &input, &caller, "pk") + cred.set_field_input(&item.id, &item.fields[0].field_id, &input, &caller, cred.unlocked().unwrap()) .unwrap(); - cred.set_field(&item.id, &item.fields[1].field_id, "opaque", &caller, "pk") + cred.set_field(&item.id, &item.fields[1].field_id, "opaque", &caller, cred.unlocked().unwrap()) .unwrap(); let current = cred.item_get(&item.id).unwrap(); let history = cred.item_versions(&item.id).unwrap().len(); @@ -243,7 +242,7 @@ fn secret_entry_keeps_oauth_cardinality_and_rolls_back_ciphertext() { }; let before = cipher(); assert_eq!( - cred.set_field_input(&item.id, &item.fields[1].field_id, &input, &caller, "pk") + cred.set_field_input(&item.id, &item.fields[1].field_id, &input, &caller, cred.unlocked().unwrap()) .err() .unwrap() .0, @@ -271,14 +270,14 @@ fn typed_secret_entry_and_bundle_normalization() { }, ) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); let input = FieldInput { - value: "two\nlines", + value: sausage::cred::items::FieldValue::Plain("two\nlines"), field_type: Some(types::FieldType::Note), key_type: None, }; - cred.set_field_input(&item.id, &item.fields[0].field_id, &input, &caller, "pk") + cred.set_field_input(&item.id, &item.fields[0].field_id, &input, &caller, cred.unlocked().unwrap()) .unwrap(); let current = cred.item_get(&item.id).unwrap(); assert_eq!(current.fields[0].field_type, types::FieldType::Note); @@ -304,7 +303,7 @@ fn typed_secret_entry_and_bundle_normalization() { assert_eq!(cred.file_request(&caller, "bundle", p).unwrap(), id); cred.approve( &id, - "yes", + sausage::cred::webauthn::Decision::Approve, Overrides { unlimited: true, ..Overrides::default() diff --git a/host/tests/cred_replay.rs b/host/tests/cred_replay.rs index 7cd9d75..5b380b6 100644 --- a/host/tests/cred_replay.rs +++ b/host/tests/cred_replay.rs @@ -35,7 +35,7 @@ fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { }], }, &caller, - "pk", + cred.unlocked().unwrap(), ) .unwrap(); (dir, cred, caller, item) @@ -53,7 +53,7 @@ fn approved_operations_and_deletes_replay() { let id = cred .file_operation_request(&caller, "edit", request.clone()) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); assert_eq!( cred.file_operation_request(&caller, "edit", request) @@ -68,7 +68,7 @@ fn approved_operations_and_deletes_replay() { let id = cred .file_delete_request(&caller, "delete", delete.clone()) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); assert_eq!( cred.file_delete_request(&caller, "delete", delete).unwrap(), @@ -88,7 +88,7 @@ fn approved_replacements_and_creations_replay() { let id = cred .file_edit_request(&caller, "replace", edit.clone()) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); assert_eq!( cred.file_edit_request(&caller, "replace", edit).unwrap(), @@ -103,7 +103,7 @@ fn approved_replacements_and_creations_replay() { let id = cred .file_operation_request(&caller, "create", request.clone()) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); assert_eq!( cred.file_operation_request(&caller, "create", request) @@ -143,11 +143,11 @@ fn grant_defaults_normalize_and_pending_requests_replay_after_deletion() { }, ) .unwrap(); - cred.approve(&delete, "yes", Overrides::default(), Some("pk")) + cred.approve(&delete, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); assert_eq!(cred.file_request(&caller, "grant", payload).unwrap(), id); assert!( - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .is_err() ); assert_eq!( @@ -184,7 +184,7 @@ fn values_are_checked_at_each_public_operation() { }, ) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); let current = cred.item_get(&item.id).unwrap(); let field = current @@ -221,7 +221,7 @@ fn values_are_checked_at_each_public_operation() { let id = cred .file_operation_request(&caller, "ordered", request) .unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); assert_eq!( cred.item_get(&item.id).unwrap().version, @@ -236,12 +236,12 @@ fn secret_retyping_checks_each_operation_only_on_approval() { &item.id, field, &FieldInput { - value: "VALUE_SENTINEL\nTAIL_SENTINEL", + value: sausage::cred::items::FieldValue::Plain("VALUE_SENTINEL\nTAIL_SENTINEL"), field_type: Some(FieldType::Note), key_type: None, }, &caller, - "pk", + cred.unlocked().unwrap(), ) .unwrap(); let current = cred.item_get(&item.id).unwrap(); @@ -271,7 +271,7 @@ fn secret_retyping_checks_each_operation_only_on_approval() { .contains("VALUE_SENTINEL") ); assert_eq!( - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .err() .unwrap() .0, @@ -280,13 +280,13 @@ fn secret_retyping_checks_each_operation_only_on_approval() { assert_eq!(cred.item_get(&item.id).unwrap().version, current.version); assert_eq!(cred.request_list().unwrap()[0].state, "pending"); let history = cred.item_versions(&item.id).unwrap().len(); - cred.set_field(&item.id, field, "single-line", &caller, "pk") + cred.set_field(&item.id, field, "single-line", &caller, cred.unlocked().unwrap()) .unwrap(); let next = cred.item_get(&item.id).unwrap(); assert_eq!(next.version, current.version + 1); assert_eq!(cred.item_versions(&item.id).unwrap().len(), history + 1); - cred.resolve_stale(&id, next.version).unwrap(); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.resolve_stale(&id, next.version, &caller, cred.unlocked().unwrap()).unwrap(); + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); } #[test] @@ -302,16 +302,16 @@ fn stale_rebases_keep_original_keyed_intent() { let id = cred .file_operation_request(&caller, "rebase", request.clone()) .unwrap(); - cred.set_field(&item.id, &item.fields[0].field_id, "opaque", &caller, "pk") + cred.set_field(&item.id, &item.fields[0].field_id, "opaque", &caller, cred.unlocked().unwrap()) .unwrap(); let current = cred.item_get(&item.id).unwrap(); - cred.resolve_stale(&id, current.version).unwrap(); + cred.resolve_stale(&id, current.version, &caller, cred.unlocked().unwrap()).unwrap(); assert_eq!( cred.file_operation_request(&caller, "rebase", request.clone()) .unwrap(), id ); - cred.approve(&id, "yes", Overrides::default(), Some("pk")) + cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) .unwrap(); assert_eq!( cred.file_operation_request(&caller, "rebase", request) diff --git a/host/tests/cred_security.rs b/host/tests/cred_security.rs new file mode 100644 index 0000000..f924ce7 --- /dev/null +++ b/host/tests/cred_security.rs @@ -0,0 +1,53 @@ +//! Destination matching fails closed before and after a credential transform. +use sausage::cred::{*, inject::Outcome, items::Item, script::{self,Script,Limits}}; +use serde_json::json; +struct Transform(serde_json::Value); +impl Script for Transform { + fn evaluate(&self,_:&str,_:&str,_:Option<&str>,_:Limits) -> std::result::Result { Ok(self.0.to_string()) } +} +fn config(host:&str,port:Option) -> Item { + serde_json::from_value(json!({"name":"destination","free_use":true,"rules":[{"scheme":"https","hosts":[host],"port":port,"path_prefixes":["/allowed/"],"methods":null}],"validate_js":null,"transform_js":"transform","fields":[]})).unwrap() +} +fn parts(uri:&str) -> http::request::Parts { http::Request::get(uri).body(()).unwrap().into_parts().0 } +#[test] +fn ports_before_and_after_transform() { + let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); + c.create_item(config("api.example",None),&caller,c.unlocked().unwrap()).unwrap(); + let Outcome::Forward(p) = c.inject(parts("https://api.example:9999/allowed/"),&caller,&Transform(json!({"headers":[{"name":"x-injected","value":"synthetic"}]}))).unwrap() else { panic!("denied") }; + assert!(!p.headers.contains_key("x-injected")); + assert!(c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({"url":"https://api.example:9999/allowed/"}))).is_err()); +} +#[test] +fn local_rules_require_ports_and_ipv6_matches() { + let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); + for host in ["localhost","127.0.0.1","::1","169.254.1.2","fe80::1"] { assert!(c.create_item(config(host,None),&caller,c.unlocked().unwrap()).is_err()); } + c.create_item(config("::1",Some(8443)),&caller,c.unlocked().unwrap()).unwrap(); + let Outcome::Forward(p) = c.inject(parts("https://[::1]:8443/allowed/"),&caller,&Transform(json!({"headers":[{"name":"x-injected","value":"synthetic"}]}))).unwrap() else { panic!("denied") }; + assert!(p.headers.contains_key("x-injected")); +} +#[test] +fn unsafe_paths_fail_before_and_after_transform() { + let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); + c.create_item(config("api.example",None),&caller,c.unlocked().unwrap()).unwrap(); + for tail in ["./x","../x","%2e/x","%2E/x","x%2fy","x%2Fy","x%5cy","x%5Cy","x\\y"] { + let url = format!("https://api.example/allowed/{tail}"); + assert!(c.inject(parts(&url),&caller,&Transform(json!({}))).is_err()); + assert!(c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({"url":url}))).is_err()); + } +} +#[test] +fn transformed_authority_and_sensitive_headers() { + let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); + c.create_item(config("api.example",None),&caller,c.unlocked().unwrap()).unwrap(); + let Outcome::Forward(p) = c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({"headers":[{"name":"host","value":"wrong.example"},{"name":"authorization","value":"synthetic"}]}))).unwrap() else { panic!("denied") }; + assert!(p.headers["authorization"].is_sensitive()); assert_eq!(p.headers["host"],"api.example"); + assert!(c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({"url":"https://user@api.example/allowed/"}))).is_err()); +} +#[test] +fn oauth2_items_fail_without_exposing_refresh_values() { + let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); let mut item = config("api.example",None); + item.fields.push(items::Field { field_id:String::new(),name:"refresh".into(),public:false,value:None,needs_value:true,field_type:types::FieldType::Oauth2RefreshToken,key_type:None }); + let item = c.create_item(item,&caller,c.unlocked().unwrap()).unwrap(); + c.set_field(&item.id,&item.fields[0].field_id,"synthetic",&caller,c.unlocked().unwrap()).unwrap(); + assert_eq!(c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({}))).err().unwrap().0,"oauth2_item"); +} diff --git a/host/tests/cred_storage.rs b/host/tests/cred_storage.rs new file mode 100644 index 0000000..5603155 --- /dev/null +++ b/host/tests/cred_storage.rs @@ -0,0 +1,30 @@ +//! Master-key startup checks use only temporary host storage and synthetic keys. +use sausage::cred::{Cred, Caller}; +use std::os::unix::fs::PermissionsExt; +#[test] +fn missing_key_in_populated_store_is_not_replaced() { + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + c.create_item(serde_json::from_value(serde_json::json!({"name":"stored","rules":[],"validate_js":null,"transform_js":"","fields":[]})).unwrap(), &Caller::default(), "test").unwrap(); + drop(c); + std::fs::remove_file(dir.path().join("cred.key")).unwrap(); + assert!(Cred::open(dir.path()).is_err()); + assert!(!dir.path().join("cred.key").exists()); +} +#[test] +fn wrong_master_key_fails_at_open_even_without_secret_fields() { + let dir = tempfile::tempdir().unwrap(); + drop(Cred::open(dir.path()).unwrap()); + std::fs::write(dir.path().join("cred.key"), [7u8;32]).unwrap(); + assert!(Cred::open(dir.path()).is_err()); +} +#[test] +fn permissive_key_is_refused_and_new_host_directory_is_private() { + let dir = tempfile::tempdir().unwrap(); + let host = dir.path().join("host"); + drop(Cred::open(&host).unwrap()); + assert_eq!(std::fs::metadata(&host).unwrap().permissions().mode() & 0o777, 0o700); + let key = host.join("cred.key"); + std::fs::set_permissions(&key,std::fs::Permissions::from_mode(0o644)).unwrap(); + assert!(Cred::open(&host).is_err()); +} diff --git a/host/tests/cred_summary.rs b/host/tests/cred_summary.rs index fef420b..69f2b51 100644 --- a/host/tests/cred_summary.rs +++ b/host/tests/cred_summary.rs @@ -21,10 +21,6 @@ fn durations_use_plain_language() { fn summaries_never_include_field_values_or_script_sources() { let value = "SECRET_SUMMARY_SENTINEL"; for operation in [ - Operation::SetFieldValue { - field: "id".into(), - value: value.into(), - }, Operation::SetTransformJs { value: value.into(), }, @@ -43,7 +39,7 @@ fn summaries_never_include_field_values_or_script_sources() { assert!(!operation_summary(&operation).contains(value)); } let input = FieldInput { - value, + value: sausage::cred::items::FieldValue::Plain(value), field_type: None, key_type: None, }; From e8732ede15ee0586b17bc632518c719000a104ff Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 6 Nov 2026 21:39:22 +0000 Subject: [PATCH 06/12] Limit background compilation and reduce cold compile cost --- host/src/process/cache.rs | 115 ++------------------------------------ host/src/process/mod.rs | 6 +- 2 files changed, 6 insertions(+), 115 deletions(-) diff --git a/host/src/process/cache.rs b/host/src/process/cache.rs index 972feea..bc81b55 100644 --- a/host/src/process/cache.rs +++ b/host/src/process/cache.rs @@ -54,13 +54,10 @@ pub(super) struct Compiler { } impl Compiler { pub fn new(directory: &Path) -> anyhow::Result> { - Self::with_opt(directory, wasmtime::OptLevel::Speed) - } - fn with_opt(directory: &Path, opt: wasmtime::OptLevel) -> anyhow::Result> { let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); let mut config = wasmtime::Config::new(); config.epoch_interruption(true); - config.cranelift_opt_level(opt); + config.cranelift_opt_level(wasmtime::OptLevel::None); let mut cache = wasmtime::CacheConfig::new(); cache.with_directory(directory); config.cache(Some(wasmtime::Cache::new(cache)?)); @@ -145,6 +142,8 @@ pub(super) fn precompile( ) -> tokio::task::JoinHandle> { tokio::spawn(async move { let mut tasks = tokio::task::JoinSet::new(); + // Leave CPU and file bandwidth for commands during startup. + let slots = Arc::new(tokio::sync::Semaphore::new(2)); for folder in ["/bin", "/usr/local/bin"] { let entries = match root.list(folder).await { Ok(entries) => entries, @@ -155,7 +154,9 @@ pub(super) fn precompile( let root = root.clone(); let compiler = compiler.clone(); let path = format!("{folder}/{}", entry.name); + let slots = slots.clone(); tasks.spawn(async move { + let _permit = slots.acquire().await?; let file = root .open( &path, @@ -190,112 +191,6 @@ mod tests { use crate::exec::{Command, Exec, Options}; use std::{future::Future, sync::atomic::Ordering}; - #[tokio::test(flavor = "multi_thread")] - #[ignore = "Temporary T15 timing probe; remove before review"] - async fn measure_world() { - let bundle = Path::new(env!("CARGO_MANIFEST_DIR")).join("../target/userland/bundle"); - let temp = tempfile::tempdir().unwrap(); - for (index, script) in ["echo hi | tr a-z A-Z", "git --version", "rg --version"] - .into_iter() - .enumerate() - { - let cache = temp.path().join(format!("cache-{index}")); - let start = std::time::Instant::now(); - let world = crate::world::World::open_with_userland( - &temp.path().join(format!("cold-{index}")), - Some(&bundle), - ) - .unwrap(); - let runtime = super::super::Runtime::new_with_cache(world, &cache).unwrap(); - let mut output = |_: crate::exec::Stream, _: &[u8]| {}; - assert_eq!( - runtime - .exec( - Command::Shell(script.into()), - Options::default(), - &mut output - ) - .await - .unwrap(), - 0 - ); - println!( - "profile={} state=cold command={script:?} seconds={:.6}", - if cfg!(debug_assertions) { - "debug" - } else { - "release" - }, - start.elapsed().as_secs_f64() - ); - let count = runtime.precompile().await.unwrap().unwrap(); - println!( - "background commands={count} seconds={:.6}", - start.elapsed().as_secs_f64() - ); - let start = std::time::Instant::now(); - assert_eq!( - runtime - .exec( - Command::Shell(script.into()), - Options::default(), - &mut output - ) - .await - .unwrap(), - 0 - ); - println!( - "state=same-host command={script:?} seconds={:.6}", - start.elapsed().as_secs_f64() - ); - drop(runtime); - let start = std::time::Instant::now(); - let world = crate::world::World::open_with_userland( - &temp.path().join(format!("warm-{index}")), - Some(&bundle), - ) - .unwrap(); - let runtime = super::super::Runtime::new_with_cache(world, &cache).unwrap(); - assert_eq!( - runtime - .exec( - Command::Shell(script.into()), - Options::default(), - &mut output - ) - .await - .unwrap(), - 0 - ); - println!( - "state=fresh-warm command={script:?} seconds={:.6}", - start.elapsed().as_secs_f64() - ); - runtime.precompile().await.unwrap().unwrap(); - } - } - - #[test] - #[ignore = "Temporary T15 timing probe; remove before review"] - fn measure_optimizer() { - let bundle = Path::new(env!("CARGO_MANIFEST_DIR")).join("../target/userland/bundle/bin"); - let temp = tempfile::tempdir().unwrap(); - for opt in [wasmtime::OptLevel::Speed, wasmtime::OptLevel::None] { - let compiler = Compiler::with_opt(&temp.path().join(format!("{opt:?}")), opt).unwrap(); - for name in ["sh", "tr", "git", "rg"] { - let bytes = std::fs::read(bundle.join(format!("{name}.wasm"))).unwrap(); - let start = std::time::Instant::now(); - compiler.compile(&bytes).unwrap(); - println!( - "optimizer={opt:?} program={name} bytes={} compile_seconds={:.6}", - bytes.len(), - start.elapsed().as_secs_f64() - ); - } - } - } - #[tokio::test(flavor = "multi_thread")] async fn command_joins_precompile_even_after_waiter_cancellation() { let temp = tempfile::tempdir().unwrap(); diff --git a/host/src/process/mod.rs b/host/src/process/mod.rs index fd525e8..2db6095 100644 --- a/host/src/process/mod.rs +++ b/host/src/process/mod.rs @@ -167,13 +167,9 @@ impl Runtime { entries: Mutex::new(HashMap::new()), next: AtomicU32::new(1), }); - runtime.precompile(); + cache::precompile(runtime.compiler.clone(), runtime.world.root.clone()); Ok(runtime) } - /// Join startup precompilation of both command folders through the shared content slots. - pub fn precompile(&self) -> tokio::task::JoinHandle> { - cache::precompile(self.compiler.clone(), self.world.root.clone()) - } /// Number of distinct program contents compiled by this runtime. pub fn compiled_programs(&self) -> usize { self.cache.lock().unwrap().len() From b3d91d37e3b8c85152582f6d455fc6b6898396d7 Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 6 Nov 2026 22:18:33 +0000 Subject: [PATCH 07/12] process: keep Cranelift's default optimization level Compiles are cached per content and guests run many times; OptLevel::None saved 12.7% compile time but slows every run. --- host/src/process/cache.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/host/src/process/cache.rs b/host/src/process/cache.rs index bc81b55..df70a73 100644 --- a/host/src/process/cache.rs +++ b/host/src/process/cache.rs @@ -57,7 +57,8 @@ impl Compiler { let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); let mut config = wasmtime::Config::new(); config.epoch_interruption(true); - config.cranelift_opt_level(wasmtime::OptLevel::None); + // Keep Cranelift's default optimization: compiles are cached per content, and guests run + // many times. OptLevel::None saved only 12.7% of compile time (T15) but slows every run. let mut cache = wasmtime::CacheConfig::new(); cache.with_directory(directory); config.cache(Some(wasmtime::Cache::new(cache)?)); From 5b3e1393f5787c1773076b71bd1f9b19f4def729 Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 6 Nov 2026 22:19:35 +0000 Subject: [PATCH 08/12] cred: complete core proof, policy, storage and injection fixes --- host/src/cred/edits.rs | 49 ++++- host/src/cred/grants.rs | 87 +++++--- host/src/cred/inject.rs | 48 ++++- host/src/cred/items.rs | 140 ++++++++++-- host/src/cred/requests.rs | 102 +++++++-- host/src/cred/store.rs | 130 ++++++++++-- host/src/cred/summary.rs | 62 +++++- host/src/cred/webauthn.rs | 353 +++++++++++++++++++++++-------- host/tests/cred.rs | 68 ++++-- host/tests/cred_accounting.rs | 111 ++++++++++ host/tests/cred_authorization.rs | 104 +++++++-- host/tests/cred_challenges.rs | 28 +-- host/tests/cred_core.rs | 77 +++++-- host/tests/cred_edits.rs | 97 +++++++-- host/tests/cred_grants.rs | 16 +- host/tests/cred_maintenance.rs | 216 +++++++++++++++++++ host/tests/cred_policy.rs | 164 +++++++++++--- host/tests/cred_presentation.rs | 84 +++++++- host/tests/cred_proofs.rs | 259 +++++++++++++++++++++++ host/tests/cred_regressions.rs | 127 ++++++++--- host/tests/cred_replay.rs | 127 ++++++++--- host/tests/cred_security.rs | 157 +++++++++++--- host/tests/cred_storage.rs | 13 +- host/tests/cred_webauthn.rs | 12 +- 24 files changed, 2223 insertions(+), 408 deletions(-) create mode 100644 host/tests/cred_accounting.rs create mode 100644 host/tests/cred_maintenance.rs create mode 100644 host/tests/cred_proofs.rs diff --git a/host/src/cred/edits.rs b/host/src/cred/edits.rs index 21d7e7d..e32c2d7 100644 --- a/host/src/cred/edits.rs +++ b/host/src/cred/edits.rs @@ -81,6 +81,8 @@ pub struct Diff { pub new: Item, pub discards_values: bool, #[serde(default)] + pub overlapping_items: Vec, + #[serde(default)] pub stale: bool, } fn check_secret( @@ -149,6 +151,7 @@ pub(crate) fn plan(db: &Connection, master: Option<&[u8; 32]>, edit: &Edit) -> R .iter() .any(|f| !f.needs_value && !new.fields.iter().any(|n| n.field_id == f.field_id)); Ok(Diff { + overlapping_items: items::overlaps(db, &new)?, old, new, discards_values, @@ -245,6 +248,7 @@ pub(crate) fn plan_revert(db: &Connection, master: Option<&[u8; 32]>, r: &Revert .iter() .any(|f| !f.needs_value && !new.fields.iter().any(|n| n.field_id == f.field_id)); Ok(Diff { + overlapping_items: items::overlaps(db, &new)?, old, new, discards_values, @@ -489,11 +493,17 @@ impl super::Cred { { return Err(Error("invalid_params")); } - items::unique_name(&self.access()?.db, &config.name, "")?; + let overlapping_items = { + let s = self.access()?; + items::unique_name(&s.db, &config.name, "")?; + let mut proposed = config.clone(); + proposed.id.clear(); + items::overlaps(&s.db, &proposed)? + }; return self.file_payload( caller, key, - serde_json::json!({"create":config,"generate_es256":generate,"requested":request}), + serde_json::json!({"create":config,"generate_es256":generate,"requested":request,"overlapping_items":overlapping_items}), ); } let edit = Edit { @@ -564,12 +574,20 @@ impl super::Cred { self.file_payload(caller, key, serde_json::json!({"edit":edit,"diff":diff})) } /// Replace a pending edit's base version after the UI reviews the current item. - pub fn resolve_stale(&self, id: &str, base_version: i64, caller: &Caller, proof: impl Into) -> Result<()> { + pub fn resolve_stale( + &self, + id: &str, + base_version: i64, + caller: &Caller, + proof: impl Into, + ) -> Result<()> { let mut s = self.access()?; let tx = s.db.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; - let binding = super::webauthn::Binding::mutation(super::webauthn::Mutation::ResolveStale, - &serde_json::json!({"request_id":id,"base_version":base_version}))?; + let binding = super::webauthn::Binding::mutation( + super::webauthn::Mutation::ResolveStale, + &serde_json::json!({"request_id":id,"base_version":base_version}), + )?; let approver = proof.into().check(&tx, &binding)?; let (payload, state): (String, String) = tx.query_row("SELECT payload,state FROM requests WHERE id=?", [id], |r| { @@ -603,9 +621,24 @@ impl super::Cred { "UPDATE requests SET payload=?2 WHERE id=?1", params![id, encoded], )?; - audit::record(&tx, "request.resolve_stale", caller, - payload.get("edit").or_else(|| payload.get("revert")).and_then(|p| p.get("item")).and_then(|v| v.as_str()), approver.as_deref())?; - tx.execute("UPDATE audit SET payload_sha256=?1 WHERE id=?2", params![super::webauthn::digest(encoded.as_bytes()), tx.last_insert_rowid()])?; + audit::record( + &tx, + "request.resolve_stale", + caller, + payload + .get("edit") + .or_else(|| payload.get("revert")) + .and_then(|p| p.get("item")) + .and_then(|v| v.as_str()), + approver.as_deref(), + )?; + tx.execute( + "UPDATE audit SET payload_sha256=?1 WHERE id=?2", + params![ + super::webauthn::digest(encoded.as_bytes()), + tx.last_insert_rowid() + ], + )?; tx.commit()?; Ok(()) } diff --git a/host/src/cred/grants.rs b/host/src/cred/grants.rs index 27da8c2..b652e99 100644 --- a/host/src/cred/grants.rs +++ b/host/src/cred/grants.rs @@ -27,27 +27,36 @@ pub(crate) fn list(db: &Connection) -> Result> { Ok(q.query_map([], read)?.collect::>()?) } fn read(r: &rusqlite::Row<'_>) -> rusqlite::Result { - Ok(Grant { - id: r.get(0)?, - items: serde_json::from_str(&r.get::<_, String>(1)?) - .map_err(|_| rusqlite::Error::InvalidQuery)?, - subject: serde_json::from_str(&r.get::<_, String>(2)?) - .map_err(|_| rusqlite::Error::InvalidQuery)?, - exp: r.get(3)?, - max_uses: r - .get::<_, Option>(4)? - .map(u64::try_from) - .transpose() - .map_err(|_| rusqlite::Error::InvalidQuery)?, - uses: u64::try_from(r.get::<_, i64>(5)?).map_err(|_| rusqlite::Error::InvalidQuery)?, - revoked: r.get(6)?, - validator: r.get(7)?, - note: r.get(8)?, - }) + Ok(Grant { + id: r.get(0)?, + items: serde_json::from_str(&r.get::<_, String>(1)?) + .map_err(|_| rusqlite::Error::InvalidQuery)?, + subject: serde_json::from_str(&r.get::<_, String>(2)?) + .map_err(|_| rusqlite::Error::InvalidQuery)?, + exp: r.get(3)?, + max_uses: r + .get::<_, Option>(4)? + .map(u64::try_from) + .transpose() + .map_err(|_| rusqlite::Error::InvalidQuery)?, + uses: u64::try_from(r.get::<_, i64>(5)?).map_err(|_| rusqlite::Error::InvalidQuery)?, + revoked: r.get(6)?, + validator: r.get(7)?, + note: r.get(8)?, + }) } fn active(db: &Connection, item: &str, caller: &Caller) -> Result> { let mut q = db.prepare("SELECT id,items,subject,exp,max_uses,uses,revoked,validator,note FROM grants WHERE revoked=0 AND (exp IS NULL OR exp>?1) AND (max_uses IS NULL OR uses>()?) + Ok(q.query_map( + params![ + now(), + item, + caller.program, + serde_json::to_string(&caller.conversations)? + ], + read, + )? + .collect::>()?) } pub(crate) fn insert( db: &Connection, @@ -98,7 +107,8 @@ impl Cred { caller: &Caller, proof: impl Into, ) -> Result { - let binding = super::webauthn::Binding::mutation(super::webauthn::Mutation::GrantCreate, &grant)?; + let binding = + super::webauthn::Binding::mutation(super::webauthn::Mutation::GrantCreate, &grant)?; grant.id = seal::identity(); grant.uses = 0; grant.revoked = false; @@ -122,6 +132,7 @@ impl Cred { .ok_or(Error("grant_missing")) } /// The harness supplies every conversation in the subtree, not only its root. + /// The harness supplies every conversation id in the terminated subtree. pub fn revoke_subjects( &self, subjects: &[String], @@ -129,8 +140,12 @@ impl Cred { proof: impl Into, ) -> Result<()> { let mut s = self.access()?; - let tx = s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; - let binding = super::webauthn::Binding::mutation(super::webauthn::Mutation::RevokeSubjects, &subjects)?; + let tx = + s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; + let binding = super::webauthn::Binding::mutation( + super::webauthn::Mutation::RevokeSubjects, + &subjects, + )?; let approver = proof.into().check(&tx, &binding)?; for subject in subjects { tx.execute( @@ -147,8 +162,13 @@ impl Cred { /// Removing access needs no assertion, including after passkey registration. pub fn revoke_grant(&self, id: &str, caller: &Caller) -> Result<()> { let mut s = self.access()?; - let tx = s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; - if tx.execute("UPDATE grants SET revoked=1,revoked_at=COALESCE(revoked_at,unixepoch()) WHERE id=?", [id])? != 1 { + let tx = + s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; + if tx.execute( + "UPDATE grants SET revoked=1,revoked_at=COALESCE(revoked_at,unixepoch()) WHERE id=?", + [id], + )? != 1 + { return Err(Error("grant_missing")); } audit::record(&tx, "grant.revoke", caller, None, None)?; @@ -157,7 +177,8 @@ impl Cred { } pub fn revoke_program(&self, program: &str, caller: &Caller) -> Result<()> { let mut s = self.access()?; - let tx = s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; + let tx = + s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; tx.execute("UPDATE grants SET revoked=1,revoked_at=COALESCE(revoked_at,unixepoch()) WHERE subject=?", [serde_json::to_string(&Subject::Program(program.into()))?])?; audit::record(&tx, "grant.revoke", caller, None, None)?; tx.commit()?; @@ -172,13 +193,23 @@ impl Cred { let master = s.master.clone(); let tx = s.db.transaction_with_behavior(TransactionBehavior::Immediate)?; - let mut grant = if item.free_use { None } else { active(&tx, &item.id, caller)?.into_iter().next() }; - if !item.free_use && grant.is_none() { return Ok(None); } - if super::items::load(&tx, &item.id)?.version != item.version { return Err(Error("stale")); } + let mut grant = if item.free_use { + None + } else { + active(&tx, &item.id, caller)?.into_iter().next() + }; + if !item.free_use && grant.is_none() { + return Ok(None); + } + if super::items::load(&tx, &item.id)?.version != item.version { + return Err(Error("stale")); + } let credential = super::items::credential(&tx, &master, item, true)?; if let Some(g) = &mut grant { let changed=tx.execute("UPDATE grants SET uses=uses+1 WHERE id=?1 AND revoked=0 AND (exp IS NULL OR exp>?2) AND (max_uses IS NULL OR uses bool { matches_rules(&item.rules, p) } fn matches_rules(rules: &[super::items::Rule], p: &Parts) -> bool { - if !safe_uri(&p.uri) { return false; } + if !safe_uri(&p.uri) { + return false; + } rules.iter().any(|r| { super::items::rule_matches_port( r, @@ -54,11 +56,16 @@ impl Cred { caller: &Caller, script: &dyn Script, ) -> Result { - if !safe_uri(&parts.uri) { return Err(Error("invalid_url")); } + if !safe_uri(&parts.uri) { + return Err(Error("invalid_url")); + } let candidates: Vec<_> = { let s = self.access()?; - s.rules.iter().filter(|(_, (_, rules))| matches_rules(rules, &parts)) - .map(|(id, (version, _))| (id.clone(), *version)).collect() + s.rules + .iter() + .filter(|(_, (_, rules))| matches_rules(rules, &parts)) + .map(|(id, (version, _))| (id.clone(), *version)) + .collect() }; if candidates.len() > 1 { return Err(Error("ambiguous_item")); @@ -67,7 +74,9 @@ impl Cred { return Ok(Outcome::Forward(parts)); }; let item = self.item_get(&id)?; - if item.version != version { return Err(Error("stale")); } + if item.version != version { + return Err(Error("stale")); + } let original_request = request(&parts)?; if item .fields @@ -76,7 +85,11 @@ impl Cred { { return Err(Error("ssh_item")); } - if item.fields.iter().any(|f| f.field_type == super::types::FieldType::Oauth2RefreshToken) { + if item + .fields + .iter() + .any(|f| f.field_type == super::types::FieldType::Oauth2RefreshToken) + { return Err(Error("oauth2_item")); } let prepared = self.reserve(&item, caller)?; @@ -152,7 +165,8 @@ impl Cred { .get("value") .and_then(Value::as_str) .ok_or(Error("transform"))?; - let mut value = http::HeaderValue::from_str(value).map_err(|_| Error("transform"))?; + let mut value = + http::HeaderValue::from_str(value).map_err(|_| Error("transform"))?; value.set_sensitive(true); new.append( http::header::HeaderName::from_bytes(name.as_bytes()) @@ -167,12 +181,24 @@ impl Cred { return Err(Error("rule_recheck")); } let authority = parts.uri.authority().ok_or(Error("rule_recheck"))?; - parts.headers.insert(http::header::HOST, - http::HeaderValue::from_str(authority.as_str()).map_err(|_| Error("rule_recheck"))?); + parts.headers.insert( + http::header::HOST, + http::HeaderValue::from_str(authority.as_str()) + .map_err(|_| Error("rule_recheck"))?, + ); Ok(()) })(); - self.access()?.db.execute("UPDATE audit SET event=?1 WHERE id=?2", - rusqlite::params![if result.is_ok() { "fetch.use" } else { "fetch.denied" }, audit_id])?; + self.access()?.db.execute( + "UPDATE audit SET event=?1 WHERE id=?2", + rusqlite::params![ + if result.is_ok() { + "fetch.use" + } else { + "fetch.denied" + }, + audit_id + ], + )?; result?; Ok(Outcome::Forward(parts)) } diff --git a/host/src/cred/items.rs b/host/src/cred/items.rs index 2e5ef07..2bff013 100644 --- a/host/src/cred/items.rs +++ b/host/src/cred/items.rs @@ -21,9 +21,19 @@ pub fn rule_matches(r: &Rule, scheme: &str, host: &str, path: &str, method: &str rule_matches_port(r, scheme, host, path, method, None) } /// Missing ports mean the scheme's default, not any port. -pub fn rule_matches_port(r: &Rule, scheme: &str, host: &str, path: &str, method: &str, port: Option) -> bool { +pub fn rule_matches_port( + r: &Rule, + scheme: &str, + host: &str, + path: &str, + method: &str, + port: Option, +) -> bool { let default = match scheme.to_ascii_lowercase().as_str() { - "http" => Some(80), "https" => Some(443), "ssh" => Some(22), _ => None, + "http" => Some(80), + "https" => Some(443), + "ssh" => Some(22), + _ => None, }; let host = host.trim_start_matches('[').trim_end_matches(']'); safe_path(path) @@ -45,16 +55,25 @@ pub fn rule_matches_port(r: &Rule, scheme: &str, host: &str, path: &str, method: } pub(crate) fn safe_path(path: &str) -> bool { let lower = path.to_ascii_lowercase(); - !path.contains('\\') && !lower.contains("%2e") && !lower.contains("%2f") - && !lower.contains("%5c") && !path.split('/').any(|s| s == "." || s == "..") + !path.contains('\\') + && !lower.contains("%2e") + && !lower.contains("%2f") + && !lower.contains("%5c") + && !path.split('/').any(|s| s == "." || s == "..") } fn local_host(host: &str) -> bool { let host = host.strip_prefix("*.").unwrap_or(host); - host.eq_ignore_ascii_case("localhost") || host.to_ascii_lowercase().ends_with(".localhost") + host.eq_ignore_ascii_case("localhost") + || host.to_ascii_lowercase().ends_with(".localhost") || host.parse::().is_ok_and(|ip| match ip { std::net::IpAddr::V4(ip) => ip.is_loopback() || ip.is_link_local(), - std::net::IpAddr::V6(ip) => ip.is_loopback() || ip.is_unicast_link_local() - || ip.to_ipv4_mapped().is_some_and(|v4| v4.is_loopback() || v4.is_link_local()), + std::net::IpAddr::V6(ip) => { + ip.is_loopback() + || ip.is_unicast_link_local() + || ip + .to_ipv4_mapped() + .is_some_and(|v4| v4.is_loopback() || v4.is_link_local()) + } }) } #[derive(Clone, Serialize, Deserialize)] @@ -155,7 +174,9 @@ pub(crate) fn validate(item: &Item) -> Result<()> { "http" | "https" | "ssh" ) || r.port == Some(0) || (r.port.is_none() && r.hosts.iter().any(|h| local_host(h))) - || r.path_prefixes.iter().any(|p| !p.starts_with('/') || !safe_path(p)) + || r.path_prefixes + .iter() + .any(|p| !p.starts_with('/') || !safe_path(p)) || r.methods.as_ref().is_some_and(|ms| { ms.iter().any(|m| { m.is_empty() || !m.bytes().all(|b| b.is_ascii_alphabetic() || b == b'-') @@ -178,6 +199,61 @@ pub(crate) fn validate(item: &Item) -> Result<()> { } Ok(()) } +/// Report every item whose rules can match the same outgoing request. +pub(crate) fn overlaps(db: &Connection, item: &Item) -> Result> { + let mut q = db.prepare("SELECT config FROM items WHERE id<>? ORDER BY id")?; + let mut ids = Vec::new(); + for row in q.query_map([&item.id], |r| r.get::<_, String>(0))? { + let other: Item = serde_json::from_str(&row?)?; + if item + .rules + .iter() + .any(|a| other.rules.iter().any(|b| rules_overlap(a, b))) + { + ids.push(other.id); + } + } + Ok(ids) +} +fn rules_overlap(a: &Rule, b: &Rule) -> bool { + let default = match a.scheme.to_ascii_lowercase().as_str() { + "http" => Some(80), + "https" => Some(443), + "ssh" => Some(22), + _ => None, + }; + a.scheme.eq_ignore_ascii_case(&b.scheme) + && a.port.or(default) == b.port.or(default) + && a.path_prefixes.iter().any(|p| { + b.path_prefixes + .iter() + .any(|q| p.starts_with(q) || q.starts_with(p)) + }) + && match (&a.methods, &b.methods) { + (Some(a), Some(b)) => a + .iter() + .any(|m| b.iter().any(|n| m.eq_ignore_ascii_case(n))), + (Some(m), None) | (None, Some(m)) => !m.is_empty(), + (None, None) => true, + } + && a.hosts.iter().any(|p| { + b.hosts.iter().any(|q| { + let p = p.to_ascii_lowercase(); + let q = q.to_ascii_lowercase(); + if p == q { + return true; + } + match (p.strip_prefix("*."), q.strip_prefix("*.")) { + (Some(p), Some(q)) => { + p.ends_with(&format!(".{q}")) || q.ends_with(&format!(".{p}")) + } + (Some(p), None) => q.ends_with(&format!(".{p}")), + (None, Some(q)) => p.ends_with(&format!(".{q}")), + (None, None) => false, + } + }) + }) +} pub(crate) fn unique_name(db: &Connection, name: &str, except: &str) -> Result<()> { let exists: bool = db.query_row( "SELECT EXISTS(SELECT 1 FROM items WHERE name=?1 AND id<>?2)", @@ -219,7 +295,10 @@ pub struct ItemVersion { /// Plain entry is bootstrap-only. Verified entry decrypts the exact bound envelope here. pub enum FieldValue<'a> { Plain(&'a str), - Encrypted { key: &'a super::entry::EntryKey, envelope: &'a super::entry::Envelope }, + Encrypted { + key: &'a super::entry::EntryKey, + envelope: &'a super::entry::Envelope, + }, } /// A secret-entry value with optional replacement metadata. Debug never includes the value. pub struct FieldInput<'a> { @@ -237,12 +316,18 @@ impl std::fmt::Debug for FieldInput<'_> { } impl Cred { /// Create an item only with an exact proof or a transaction-checked bootstrap value. - pub fn create_item(&self, item: Item, caller: &Caller, proof: impl Into) -> Result { + pub fn create_item( + &self, + item: Item, + caller: &Caller, + proof: impl Into, + ) -> Result { let mut s = self.access()?; let tx = s.db.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; validate(&item)?; - let binding = super::webauthn::Binding::mutation(super::webauthn::Mutation::CreateItem, &item)?; + let binding = + super::webauthn::Binding::mutation(super::webauthn::Mutation::CreateItem, &item)?; let approver = proof.into().check(&tx, &binding)?; let item = insert_new(&tx, item, caller, approver.as_deref())?; tx.commit()?; @@ -304,23 +389,38 @@ impl Cred { ) -> Result<()> { let mut s = self.access()?; let key = s.master.clone(); - let tx = s.db.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; + let tx = + s.db.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; let proof = proof.into(); - if matches!(&proof, super::webauthn::Proof::Verified(_)) && matches!(&input.value, FieldValue::Plain(_)) { + if matches!(&proof, super::webauthn::Proof::Verified(_)) + && matches!(&input.value, FieldValue::Plain(_)) + { return Err(Error("binding_mismatch")); } - let hash = match &input.value { FieldValue::Plain(_) => String::new(), FieldValue::Encrypted { envelope, .. } => envelope.sha256() }; - let approver = proof.check(&tx, &super::webauthn::Binding::SecretEntry { - item: item.into(), field: field.into(), ciphertext_sha256: hash, - field_type: input.field_type.clone(), key_type: input.key_type.clone(), - })?; + let hash = match &input.value { + FieldValue::Plain(_) => String::new(), + FieldValue::Encrypted { envelope, .. } => envelope.sha256(), + }; + let approver = proof.check( + &tx, + &super::webauthn::Binding::SecretEntry { + item: item.into(), + field: field.into(), + ciphertext_sha256: hash, + field_type: input.field_type.clone(), + key_type: input.key_type.clone(), + }, + )?; let decrypted; let value = match &input.value { FieldValue::Plain(value) => *value, FieldValue::Encrypted { key, envelope } => { - decrypted = zeroize::Zeroizing::new(key.decrypt(envelope).map_err(|_| Error("secret_envelope"))?); + decrypted = zeroize::Zeroizing::new( + key.decrypt(envelope) + .map_err(|_| Error("secret_envelope"))?, + ); std::str::from_utf8(&decrypted).map_err(|_| Error("field_invalid"))? - }, + } }; let mut config = load(&tx, item)?; let index = config diff --git a/host/src/cred/requests.rs b/host/src/cred/requests.rs index 90b0bef..89e81dd 100644 --- a/host/src/cred/requests.rs +++ b/host/src/cred/requests.rs @@ -27,7 +27,8 @@ pub struct Request { pub decision: Option, pub approver: Option, } -#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] pub struct Overrides { #[serde(default)] pub unlimited: bool, @@ -93,7 +94,8 @@ impl Cred { }), }; Ok( - ((state == "pending" && expires > now()) || (state == "approved" && usable)) + (((state == "pending" || state == "denied") && expires > now()) + || (state == "approved" && usable)) .then_some(id), ) } @@ -122,6 +124,9 @@ impl Cred { payload.items.sort(); payload.items.dedup(); payload.duration_secs = Some(payload.duration_secs.unwrap_or(3600)); + if payload.duration_secs.is_some_and(|d| d == 0 || d > 86400) { + return Err(Error("invalid_duration")); + } if payload.validator.as_deref() == Some("") { payload.validator = None; } @@ -155,7 +160,7 @@ impl Cred { if normalised(&serde_json::from_str(&prior)?) != normalised(&payload) { return Err(Error("key_conflict")); } - if state == "pending" && expires > now() { + if (state == "pending" || state == "denied") && expires > now() { return Ok(id); } if state == "approved" @@ -231,24 +236,54 @@ impl Cred { .filter(|r| r.state != "pending") .collect()) } + /// Build a binding from the exact stored payload, not a preview supplied by the world. + pub fn decision_binding( + &self, + id: &str, + decision: super::webauthn::Decision, + overrides: Overrides, + ) -> Result { + let s = self.access()?; + let payload: String = + s.db.query_row("SELECT payload FROM requests WHERE id=?", [id], |r| { + r.get(0) + })?; + Ok(super::webauthn::Binding::Decision { + request_id: id.into(), + decision, + overrides, + payload_sha256: super::webauthn::digest(payload.as_bytes()), + }) + } pub fn approve( &self, id: &str, - decision: &str, + decision: super::webauthn::Decision, overrides: Overrides, - approver: Option<&str>, + proof: impl Into, ) -> Result<()> { - self.decide(id, decision, Some(overrides), approver) + if decision != super::webauthn::Decision::Approve { + return Err(Error("invalid_decision")); + } + self.decide(id, decision, Some(overrides), proof.into()) } - pub fn deny(&self, id: &str, decision: &str, approver: Option<&str>) -> Result<()> { - self.decide(id, decision, None, approver) + pub fn deny( + &self, + id: &str, + decision: super::webauthn::Decision, + proof: impl Into, + ) -> Result<()> { + if decision != super::webauthn::Decision::Deny { + return Err(Error("invalid_decision")); + } + self.decide(id, decision, None, proof.into()) } fn decide( &self, id: &str, - decision: &str, + decision: super::webauthn::Decision, overrides: Option, - approver: Option<&str>, + proof: super::webauthn::Proof, ) -> Result<()> { let mut s = self.access()?; let master = s.master.clone(); @@ -275,6 +310,16 @@ impl Cred { )) }, )?; + let approver = proof.check( + &tx, + &super::webauthn::Binding::Decision { + request_id: id.into(), + decision, + overrides: overrides.clone().unwrap_or_default(), + payload_sha256: super::webauthn::digest(payload.as_bytes()), + }, + )?; + let approver = approver.as_deref(); let subject: Subject = serde_json::from_str(&subject)?; if state == "expired" { return Err(Error("request_expired")); @@ -299,6 +344,15 @@ impl Cred { let mut issued_grant = None; let state = if let Some(o) = overrides { let parsed: serde_json::Value = serde_json::from_str(&payload)?; + if parsed.get("items").is_none() + && parsed.get("grant_create").is_none() + && o != Overrides::default() + { + return Err(Error("ignored_overrides")); + } + if o.unlimited && o.max_uses.is_some() { + return Err(Error("invalid_uses")); + } if let Some(edit) = parsed.get("edit") { let mut edit: super::edits::Edit = serde_json::from_value(edit.clone())?; if let Some(requested) = parsed.get("requested") { @@ -358,10 +412,31 @@ impl Cred { grant.id = seal::identity(); grant.uses = 0; grant.revoked = false; + if let Some(duration) = o.duration_secs { + if duration == 0 { + return Err(Error("invalid_duration")); + } + grant.exp = Some( + now() + .checked_add( + i64::try_from(duration).map_err(|_| Error("invalid_duration"))?, + ) + .ok_or(Error("invalid_duration"))?, + ); + } else if grant.exp.is_none() { + grant.exp = Some(now() + 3600); + } + grant.max_uses = if o.unlimited { + None + } else { + o.max_uses.or(grant.max_uses) + }; + grant.validator = o.validator.or(grant.validator); grants::insert(&tx, &grant, &caller, approver)?; + issued_grant = Some(grant.id); } else if let Some(target) = parsed.get("grant_revoke") { let target = target.as_str().ok_or(Error("invalid_params"))?; - if tx.execute("UPDATE grants SET revoked=1 WHERE id=?", [target])? != 1 { + if tx.execute("UPDATE grants SET revoked=1,revoked_at=COALESCE(revoked_at,unixepoch()) WHERE id=?", [target])? != 1 { return Err(Error("grant_missing")); } audit::record(&tx, "grant.revoke", &caller, None, approver)?; @@ -406,11 +481,12 @@ impl Cred { "denied" }; tx.execute( - "UPDATE requests SET state=?2,decision=?3,approver=?4,grant_id=?5 WHERE id=?1", - params![id, state, decision, approver, issued_grant], + "UPDATE requests SET state=?2,decision=?3,approver=?4,grant_id=?5,decided_at=unixepoch() WHERE id=?1", + params![id, state, match decision { super::webauthn::Decision::Approve => "approve", super::webauthn::Decision::Deny => "deny" }, approver, issued_grant], )?; audit::record(&tx, state, &caller, None, approver)?; tx.commit()?; + s.refresh_rules()?; let _ = self.decided.send(id.to_owned()); Ok(()) } diff --git a/host/src/cred/store.rs b/host/src/cred/store.rs index 48118b8..5da46d3 100644 --- a/host/src/cred/store.rs +++ b/host/src/cred/store.rs @@ -3,63 +3,147 @@ use super::{ error::{Error, Result}, schema, seal, }; +use rusqlite::OptionalExtension; use std::{ io::{Read, Write}, - os::unix::fs::OpenOptionsExt, + os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt}, path::Path, sync::{Mutex, MutexGuard}, }; pub(crate) struct Store { pub db: rusqlite::Connection, pub master: zeroize::Zeroizing<[u8; 32]>, + pub rules: std::collections::HashMap)>, +} +impl Store { + pub fn refresh_rules(&mut self) -> Result<()> { + self.rules = rule_index(&self.db)?; + Ok(()) + } +} +fn rule_index( + db: &rusqlite::Connection, +) -> Result)>> { + let mut q = db.prepare("SELECT config FROM items")?; + q.query_map([], |r| r.get::<_, String>(0))? + .map(|r| { + let item: super::items::Item = serde_json::from_str(&r?)?; + Ok((item.id, (item.version, item.rules))) + }) + .collect() } pub struct Cred { pub(crate) store: Mutex, pub(crate) decided: tokio::sync::broadcast::Sender, pub(crate) filed: tokio::sync::broadcast::Sender, } +const KEY_CHECK: &[u8] = b"sausage/credentials/master/v1"; impl Cred { + /// Open local host storage. The host resolves systemd credentials, not this library. pub fn open(host_dir: &Path) -> Result { - std::fs::create_dir_all(host_dir)?; - let path = std::env::var_os("CREDENTIALS_DIRECTORY") - .map(|p| std::path::PathBuf::from(p).join("sausage-cred-key")) - .unwrap_or_else(|| host_dir.join("cred.key")); - if std::env::var_os("CREDENTIALS_DIRECTORY").is_none() { - match std::fs::OpenOptions::new() - .write(true) - .create_new(true) - .mode(0o600) - .open(&path) - { - Ok(mut file) => { - file.write_all(&seal::random::<32>())?; - file.sync_all()?; - } - Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {} - Err(e) => return Err(e.into()), + Self::open_with_key(host_dir, &host_dir.join("cred.key")) + } + pub fn open_with_key(host_dir: &Path, key_path: &Path) -> Result { + std::fs::DirBuilder::new() + .recursive(true) + .mode(0o700) + .create(host_dir)?; + std::fs::set_permissions(host_dir, std::fs::Permissions::from_mode(0o700))?; + let db = rusqlite::Connection::open(host_dir.join("cred.sqlite"))?; + db.busy_timeout(std::time::Duration::from_secs(5))?; + db.execute_batch(schema::DDL)?; + let check: Option> = db + .query_row("SELECT value FROM meta WHERE key='master'", [], |r| { + r.get(0) + }) + .optional()?; + match std::fs::metadata(key_path) { + Ok(meta) if meta.permissions().mode() & 0o077 != 0 => { + return Err(Error("master_key_permissions")); } + Ok(_) => {} + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + let populated: bool = db.query_row( + "SELECT EXISTS(SELECT 1 FROM items) OR EXISTS(SELECT 1 FROM fields)", + [], + |r| r.get(0), + )?; + if populated || check.is_some() { + return Err(Error("master_key_missing")); + } + let parent = key_path + .parent() + .filter(|p| !p.as_os_str().is_empty()) + .unwrap_or(Path::new(".")); + let temp = parent.join(format!(".cred-key-{}", seal::identity())); + let mut file = std::fs::OpenOptions::new() + .write(true) + .create_new(true) + .mode(0o600) + .open(&temp)?; + let key = zeroize::Zeroizing::new(seal::random::<32>()); + file.write_all(key.as_ref())?; + file.sync_all()?; + std::fs::rename(&temp, key_path)?; + std::fs::File::open(parent)?.sync_all()?; + } + Err(e) => return Err(e.into()), } let mut bytes = zeroize::Zeroizing::new(Vec::new()); - std::fs::File::open(path)?.read_to_end(&mut bytes)?; + std::fs::File::open(key_path)?.read_to_end(&mut bytes)?; let master = zeroize::Zeroizing::new( bytes .as_slice() .try_into() .map_err(|_| Error("master_key"))?, ); - let db = rusqlite::Connection::open(host_dir.join("cred.sqlite"))?; - db.busy_timeout(std::time::Duration::from_secs(5))?; - db.execute_batch(schema::DDL)?; + match check { + Some(check) => { + let value = + seal::open(&master, "master-check", &check).map_err(|_| Error("master_key"))?; + if value.as_slice() != KEY_CHECK { + return Err(Error("master_key")); + } + } + None => { + let populated: bool = db.query_row( + "SELECT EXISTS(SELECT 1 FROM items) OR EXISTS(SELECT 1 FROM fields)", + [], + |r| r.get(0), + )?; + if populated { + return Err(Error("master_key_check_missing")); + } + let check = seal::seal(&master, "master-check", KEY_CHECK)?; + db.execute("INSERT INTO meta(key,value) VALUES('master',?1)", [check])?; + } + } let (decided, _) = tokio::sync::broadcast::channel(64); let (filed, _) = tokio::sync::broadcast::channel(64); + let rules = rule_index(&db)?; let cred = Self { - store: Mutex::new(Store { db, master }), + store: Mutex::new(Store { db, master, rules }), decided, filed, }; cred.expire_requests()?; Ok(cred) } + /// D57 maintenance. The harness calls this daily. Item versions remain intact. + pub fn prune(&self, now: i64) -> Result<()> { + let mut s = self.access()?; + let tx = + s.db.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; + tx.execute( + "DELETE FROM audit WHERE time'pending' AND (CASE WHEN state='expired' THEN expires ELSE decided_at END) Result> { self.store.lock().map_err(|_| Error("storage")) } diff --git a/host/src/cred/summary.rs b/host/src/cred/summary.rs index 7316f94..2dec79d 100644 --- a/host/src/cred/summary.rs +++ b/host/src/cred/summary.rs @@ -1,4 +1,4 @@ -//! Public approval summaries. Do not interpolate field values or script sources. +//! Public approval summaries expose policy and public values, never secrets or script sources. pub fn human_duration(mut seconds: u64) -> String { let mut parts = Vec::new(); for (size, unit) in [ @@ -26,6 +26,10 @@ fn text(value: &str) -> String { let mut out = String::new(); for c in value.chars() { match c { + '\u{200b}'..='\u{200f}' + | '\u{202a}'..='\u{202e}' + | '\u{2060}'..='\u{206f}' + | '\u{feff}' => {} '\n' | '\r' => out.push(' '), '&' => out.push_str("&"), '<' => out.push_str("<"), @@ -39,15 +43,57 @@ fn text(value: &str) -> String { } out } +fn rules_text(rules: &[super::items::Rule]) -> String { + let mut hosts = Vec::new(); + for rule in rules { + let port = rule + .port + .unwrap_or(match rule.scheme.to_ascii_lowercase().as_str() { + "http" => 80, + "https" => 443, + "ssh" => 22, + _ => 0, + }); + for host in &rule.hosts { + hosts.push(format!( + "{} host {}, port {}{}", + text(&rule.scheme), + text(host), + port, + if host.starts_with("*.") { + " (wildcard: check the public suffix)" + } else { + "" + } + )); + } + } + format!("Rules: {}.", hosts.join(", ")) +} +fn creation(config: &super::items::Item) -> String { + format!( + "Create item “{}”. {} {} {}", + text(&config.name), + if config.free_use { + "Anyone can use it without a grant." + } else { + "It requires a grant." + }, + rules_text(&config.rules), + if config.transform_js.is_empty() { + "It has no transformation script." + } else { + "It runs a transformation script." + } + ) +} pub fn operation_summary(operation: &super::edits::Operation) -> String { use super::edits::Operation::*; match operation { - CreateItem { config } => format!("Create item “{}”.", text(&config.name)), - GenerateEs256Item { config } => { - format!("Create item “{}” with a new ES256 key.", text(&config.name)) - } + CreateItem { config } => creation(config), + GenerateEs256Item { config } => format!("{} Generate a new ES256 key.", creation(config)), SetName { name } => format!("Rename the item to “{}”.", text(name)), - SetRules { .. } => "Replace the access rules. Review the rules in Details.".into(), + SetRules { rules } => format!("Replace the access rules. {}", rules_text(rules)), SetFreeUse { enabled: true } => { "Allow anyone to use this item without a grant, within its rules.".into() } @@ -60,7 +106,9 @@ pub fn operation_summary(operation: &super::edits::Operation) -> String { if field.public { "public" } else { "secret" }, text(&field.name) ), - SetFieldValue { .. } => "Change a public field value.".into(), + SetFieldValue { field, value } => { + format!("Set public field “{}” to “{}”.", text(field), text(value)) + } SetFieldType { .. } => "Change a field type. Review the type in Details.".into(), RenameField { name, .. } => format!("Rename a field to “{}”.", text(name)), RemoveField { .. } => "Remove a field and permanently discard its value.".into(), diff --git a/host/src/cred/webauthn.rs b/host/src/cred/webauthn.rs index ba01583..b02cab5 100644 --- a/host/src/cred/webauthn.rs +++ b/host/src/cred/webauthn.rs @@ -1,156 +1,337 @@ //! Passkey assertions produce private, single-use proofs for exact host-owned bindings. //! Bootstrap proofs remain valid only while the decision transaction finds no passkeys. //! The caller serializes access to this manager and supplies the credentials database. +use super::{requests::Overrides, types::FieldType}; use anyhow::{Result, bail}; use rusqlite::{Connection, params}; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, time::{Duration, Instant}}; +use std::{ + collections::HashMap, + time::{Duration, Instant}, +}; use webauthn_rs::prelude::*; -use super::{requests::Overrides, types::FieldType}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all="snake_case")] -pub enum Decision { Approve, Deny } +#[serde(rename_all = "snake_case")] +pub enum Decision { + Approve, + Deny, +} #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all="snake_case")] -pub enum Mutation { CreateItem, GrantCreate, RevokeSubjects, ResolveStale } +#[serde(rename_all = "snake_case")] +pub enum Mutation { + CreateItem, + GrantCreate, + RevokeSubjects, + ResolveStale, +} #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(tag="type", deny_unknown_fields)] +#[serde(tag = "type", deny_unknown_fields)] pub enum Binding { - Decision { request_id:String, decision:Decision, overrides:Overrides, payload_sha256:String }, - SecretEntry { item:String, field:String, ciphertext_sha256:String, field_type:Option, key_type:Option }, - Mutation { action:Mutation, parameters_sha256:String }, - Enrollment { label:String }, + Decision { + request_id: String, + decision: Decision, + overrides: Overrides, + payload_sha256: String, + }, + SecretEntry { + item: String, + field: String, + ciphertext_sha256: String, + field_type: Option, + key_type: Option, + }, + Mutation { + action: Mutation, + parameters_sha256: String, + }, + Enrollment { + label: String, + }, } impl Binding { - pub fn mutation(action:Mutation, parameters:&impl Serialize) -> super::Result { - Ok(Self::Mutation { action, parameters_sha256:digest(&serde_json::to_vec(parameters)?) }) + pub fn mutation(action: Mutation, parameters: &impl Serialize) -> super::Result { + Ok(Self::Mutation { + action, + parameters_sha256: digest(&serde_json::to_vec(parameters)?), + }) } } -pub(crate) fn digest(bytes:&[u8]) -> String { +pub(crate) fn digest(bytes: &[u8]) -> String { use sha2::{Digest, Sha256}; hex::encode(Sha256::digest(bytes)) } /// Only successful WebAuthn verification constructs this value. It cannot be cloned. -pub struct Verified { credential:CredentialID, binding:Binding } +pub struct Verified { + credential: CredentialID, + binding: Binding, +} impl Verified { - pub fn credential(&self) -> &CredentialID { &self.credential } - pub fn binding(&self) -> &Binding { &self.binding } + pub fn credential(&self) -> &CredentialID { + &self.credential + } + pub fn binding(&self) -> &Binding { + &self.binding + } } /// The constructor checks the registry. Every mutation checks it again in its transaction. #[derive(Clone, Copy)] pub struct Unlocked(()); -pub enum Proof { Verified(Verified), Unlocked(Unlocked) } -impl From for Proof { fn from(v:Verified) -> Self { Self::Verified(v) } } -impl From for Proof { fn from(v:Unlocked) -> Self { Self::Unlocked(v) } } +pub enum Proof { + Verified(Verified), + Unlocked(Unlocked), +} +impl From for Proof { + fn from(v: Verified) -> Self { + Self::Verified(v) + } +} +impl From for Proof { + fn from(v: Unlocked) -> Self { + Self::Unlocked(v) + } +} impl Proof { - pub(crate) fn check(self, db:&Connection, expected:&Binding) -> super::Result> { + pub(crate) fn check( + self, + db: &Connection, + expected: &Binding, + ) -> super::Result> { match self { Self::Unlocked(_) => { - let unlocked:bool = db.query_row("SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)",[],|r|r.get(0))?; - if !unlocked { return Err(super::Error("assertion_required")); } + let unlocked: bool = db.query_row( + "SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)", + [], + |r| r.get(0), + )?; + if !unlocked { + return Err(super::Error("assertion_required")); + } Ok(None) - }, + } Self::Verified(v) => { - if &v.binding != expected { return Err(super::Error("binding_mismatch")); } + if &v.binding != expected { + return Err(super::Error("binding_mismatch")); + } let id = serde_json::to_string(&v.credential)?; - let registered:bool = db.query_row("SELECT EXISTS(SELECT 1 FROM passkey_credentials WHERE id=?)",[&id],|r|r.get(0))?; - if !registered { return Err(super::Error("assertion_required")); } + let registered: bool = db.query_row( + "SELECT EXISTS(SELECT 1 FROM passkey_credentials WHERE id=?)", + [&id], + |r| r.get(0), + )?; + if !registered { + return Err(super::Error("assertion_required")); + } Ok(Some(id)) - }, + } } } } impl super::Cred { pub fn unlocked(&self) -> super::Result { let s = self.access()?; - let unlocked:bool = s.db.query_row("SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)",[],|r|r.get(0))?; - if !unlocked { return Err(super::Error("assertion_required")); } + let unlocked: bool = s.db.query_row( + "SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)", + [], + |r| r.get(0), + )?; + if !unlocked { + return Err(super::Error("assertion_required")); + } Ok(Unlocked(())) } } #[derive(Serialize, Deserialize)] -pub struct Gate { pub id:String, pub response:PublicKeyCredential } +pub struct Gate { + pub id: String, + pub response: PublicKeyCredential, +} #[derive(Serialize, Deserialize)] -pub struct Challenge { pub id:String, pub options:T } -struct Pending { deadline:Instant, value:T } +pub struct Challenge { + pub id: String, + pub options: T, +} +struct Pending { + deadline: Instant, + value: T, +} pub struct Passkeys<'a> { - db:&'a Connection, webauthn:Webauthn, - registrations:HashMap>, - assertions:HashMap>, + db: &'a Connection, + webauthn: Webauthn, + registrations: HashMap>, + assertions: HashMap>, } impl<'a> Passkeys<'a> { - pub fn new(db:&'a Connection,rp_id:&str,origin:&str) -> Result { + pub fn new(db: &'a Connection, rp_id: &str, origin: &str) -> Result { let origin = Url::parse(origin)?; - let webauthn = WebauthnBuilder::new(rp_id,&origin)?.build()?; + let webauthn = WebauthnBuilder::new(rp_id, &origin)?.build()?; db.execute_batch("CREATE TABLE IF NOT EXISTS passkey_credentials(id TEXT PRIMARY KEY,label TEXT NOT NULL,credential TEXT NOT NULL)")?; - Ok(Self { db, webauthn, registrations:HashMap::new(), assertions:HashMap::new() }) + Ok(Self { + db, + webauthn, + registrations: HashMap::new(), + assertions: HashMap::new(), + }) } /// Database errors leave the manager locked. pub fn is_unlocked(&self) -> bool { - self.db.query_row("SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)",[],|r|r.get(0)).unwrap_or(false) + self.db + .query_row( + "SELECT NOT EXISTS(SELECT 1 FROM passkey_credentials)", + [], + |r| r.get(0), + ) + .unwrap_or(false) } fn credentials(&self) -> Result> { - let mut q = self.db.prepare("SELECT credential FROM passkey_credentials")?; - q.query_map([],|r|r.get::<_,String>(0))?.map(|r|Ok(serde_json::from_str(&r?)?)).collect() + let mut q = self + .db + .prepare("SELECT credential FROM passkey_credentials")?; + q.query_map([], |r| r.get::<_, String>(0))? + .map(|r| Ok(serde_json::from_str(&r?)?)) + .collect() } - pub fn start_registration(&mut self,label:String,gate:Option) -> Result> { + pub fn start_registration( + &mut self, + label: String, + gate: Option, + ) -> Result> { let gated = gate.is_some(); match gate { None if !self.is_unlocked() => bail!("enrollment assertion required"), - None => {}, - Some(Gate { id,response }) => { - let proof = self.finish_assertion(&id,response)?; - if proof.binding != (Binding::Enrollment { label:label.clone() }) { bail!("invalid enrollment gate"); } - }, + None => {} + Some(Gate { id, response }) => { + let proof = self.finish_assertion(&id, response)?; + if proof.binding + != (Binding::Enrollment { + label: label.clone(), + }) + { + bail!("invalid enrollment gate"); + } + } } - let exclude = self.credentials()?.iter().map(|p|p.cred_id().clone()).collect(); - let (options,state) = self.webauthn.start_passkey_registration(Uuid::new_v4(),&label,&label,Some(exclude))?; + let exclude = self + .credentials()? + .iter() + .map(|p| p.cred_id().clone()) + .collect(); + let (options, state) = self.webauthn.start_passkey_registration( + Uuid::new_v4(), + &label, + &label, + Some(exclude), + )?; trim(&mut self.registrations); let id = Uuid::new_v4().to_string(); - self.registrations.insert(id.clone(),Pending { deadline:Instant::now()+Duration::from_secs(300), value:(label,gated,state) }); - Ok(Challenge { id,options }) + self.registrations.insert( + id.clone(), + Pending { + deadline: Instant::now() + Duration::from_secs(300), + value: (label, gated, state), + }, + ); + Ok(Challenge { id, options }) } - pub fn finish_registration(&mut self,id:&str,response:RegisterPublicKeyCredential) -> Result { + pub fn finish_registration( + &mut self, + id: &str, + response: RegisterPublicKeyCredential, + ) -> Result { let unlocked = self.is_unlocked(); - let (label,gated,state) = pending(&mut self.registrations,id)?; - if !*gated && !unlocked { bail!("enrollment assertion required"); } - let credential = self.webauthn.finish_passkey_registration(&response,state)?; - self.db.execute("INSERT INTO passkey_credentials(id,label,credential) VALUES(?1,?2,?3)",params![serde_json::to_string(credential.cred_id())?,label,serde_json::to_string(&credential)?])?; + let (label, gated, state) = pending(&mut self.registrations, id)?; + if !*gated && !unlocked { + bail!("enrollment assertion required"); + } + let credential = self + .webauthn + .finish_passkey_registration(&response, state)?; + self.db.execute( + "INSERT INTO passkey_credentials(id,label,credential) VALUES(?1,?2,?3)", + params![ + serde_json::to_string(credential.cred_id())?, + label, + serde_json::to_string(&credential)? + ], + )?; self.registrations.remove(id); Ok(credential) } - pub fn start_assertion(&mut self,binding:Binding) -> Result> { - let (options,state) = self.webauthn.start_passkey_authentication(&self.credentials()?)?; + pub fn start_assertion( + &mut self, + binding: Binding, + ) -> Result> { + let (options, state) = self + .webauthn + .start_passkey_authentication(&self.credentials()?)?; trim(&mut self.assertions); let id = Uuid::new_v4().to_string(); - self.assertions.insert(id.clone(),Pending { deadline:Instant::now()+Duration::from_secs(300), value:(binding,state) }); - Ok(Challenge { id,options }) + self.assertions.insert( + id.clone(), + Pending { + deadline: Instant::now() + Duration::from_secs(300), + value: (binding, state), + }, + ); + Ok(Challenge { id, options }) } - pub fn finish_assertion(&mut self,id:&str,response:PublicKeyCredential) -> Result { - let (binding,state) = pending(&mut self.assertions,id)?; + pub fn finish_assertion( + &mut self, + id: &str, + response: PublicKeyCredential, + ) -> Result { + let (binding, state) = pending(&mut self.assertions, id)?; let binding = binding.clone(); - let result = self.webauthn.finish_passkey_authentication(&response,state)?; + let result = self + .webauthn + .finish_passkey_authentication(&response, state)?; let mut credentials = self.credentials()?; - let credential = credentials.iter_mut().find(|p|p.cred_id()==result.cred_id()).ok_or_else(||anyhow::anyhow!("unregistered passkey"))?; + let credential = credentials + .iter_mut() + .find(|p| p.cred_id() == result.cred_id()) + .ok_or_else(|| anyhow::anyhow!("unregistered passkey"))?; let stored = serde_json::to_value(&*credential)?; - let counter = stored["cred"]["counter"].as_u64().ok_or_else(||anyhow::anyhow!("invalid stored passkey counter"))?; - if (counter>0 || result.counter()>0) && u64::from(result.counter())<=counter { bail!("passkey counter did not increase"); } + let counter = stored["cred"]["counter"] + .as_u64() + .ok_or_else(|| anyhow::anyhow!("invalid stored passkey counter"))?; + if (counter > 0 || result.counter() > 0) && u64::from(result.counter()) <= counter { + bail!("passkey counter did not increase"); + } credential.update_credential(&result); - self.db.execute("UPDATE passkey_credentials SET credential=?1 WHERE id=?2",params![serde_json::to_string(credential)?,serde_json::to_string(result.cred_id())?])?; + self.db.execute( + "UPDATE passkey_credentials SET credential=?1 WHERE id=?2", + params![ + serde_json::to_string(credential)?, + serde_json::to_string(result.cred_id())? + ], + )?; self.assertions.remove(id); - Ok(Verified { credential:result.cred_id().clone(),binding }) + Ok(Verified { + credential: result.cred_id().clone(), + binding, + }) } } -fn pending<'a,T>(map:&'a mut HashMap>,id:&str) -> Result<&'a T> { - let expired = map.get(id).ok_or_else(||anyhow::anyhow!("unknown or consumed challenge"))?.deadline<=Instant::now(); - if expired { map.remove(id); bail!("expired challenge"); } +fn pending<'a, T>(map: &'a mut HashMap>, id: &str) -> Result<&'a T> { + let expired = map + .get(id) + .ok_or_else(|| anyhow::anyhow!("unknown or consumed challenge"))? + .deadline + <= Instant::now(); + if expired { + map.remove(id); + bail!("expired challenge"); + } Ok(&map.get(id).expect("checked challenge").value) } -fn trim(map:&mut HashMap>) { - map.retain(|_,p|p.deadline>Instant::now()); - if map.len()>=32 { - let id = map.iter().min_by_key(|(_,p)|p.deadline).map(|(id,_)|id.clone()).expect("full challenge map"); +fn trim(map: &mut HashMap>) { + map.retain(|_, p| p.deadline > Instant::now()); + if map.len() >= 32 { + let id = map + .iter() + .min_by_key(|(_, p)| p.deadline) + .map(|(id, _)| id.clone()) + .expect("full challenge map"); map.remove(&id); } } @@ -159,18 +340,20 @@ mod tests { use super::*; #[test] fn expired_assertion() -> Result<()> { - use webauthn_authenticator_rs::{WebauthnAuthenticator,softpasskey::SoftPasskey}; + use webauthn_authenticator_rs::{WebauthnAuthenticator, softpasskey::SoftPasskey}; let db = Connection::open_in_memory()?; - let mut host = Passkeys::new(&db,"localhost","http://localhost:8000")?; - let start = host.start_registration("test".into(),None)?; + let mut host = Passkeys::new(&db, "localhost", "http://localhost:8000")?; + let start = host.start_registration("test".into(), None)?; let mut auth = WebauthnAuthenticator::new(SoftPasskey::new(true)); let origin = Url::parse("http://localhost:8000")?; - let response = auth.do_registration(origin.clone(),start.options)?; - host.finish_registration(&start.id,response)?; - let start = host.start_assertion(Binding::Enrollment { label:"next".into() })?; - let response = auth.do_authentication(origin,start.options)?; - host.assertions.get_mut(&start.id).unwrap().deadline=Instant::now(); - assert!(host.finish_assertion(&start.id,response).is_err()); + let response = auth.do_registration(origin.clone(), start.options)?; + host.finish_registration(&start.id, response)?; + let start = host.start_assertion(Binding::Enrollment { + label: "next".into(), + })?; + let response = auth.do_authentication(origin, start.options)?; + host.assertions.get_mut(&start.id).unwrap().deadline = Instant::now(); + assert!(host.finish_assertion(&start.id, response).is_err()); assert!(!host.assertions.contains_key(&start.id)); Ok(()) } diff --git a/host/tests/cred.rs b/host/tests/cred.rs index 1a048eb..9b058e3 100644 --- a/host/tests/cred.rs +++ b/host/tests/cred.rs @@ -75,7 +75,9 @@ fn inject_selection_idempotency_and_subtree() { c.inject(parts("api.example"), &root, &Fake).unwrap(), Outcome::Forward(_) )); - let i = c.create_item(item(false), &root, c.unlocked().unwrap()).unwrap(); + let i = c + .create_item(item(false), &root, c.unlocked().unwrap()) + .unwrap(); let first = match c.inject(parts("api.example"), &root, &Fake).unwrap() { Outcome::Denied { item, request } => { assert_eq!(item, "token"); @@ -89,10 +91,21 @@ fn inject_selection_idempotency_and_subtree() { }; assert_eq!(first, second); assert_eq!(c.request_list().unwrap().len(), 1); - c.set_field(&i.id, &i.fields[0].field_id, "opaque", &root, c.unlocked().unwrap()) - .unwrap(); - c.approve(&first, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap(); + c.set_field( + &i.id, + &i.fields[0].field_id, + "opaque", + &root, + c.unlocked().unwrap(), + ) + .unwrap(); + c.approve( + &first, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); let child = Caller { program: "/bin/tool.wasm".into(), pid: 43, @@ -133,10 +146,18 @@ fn free_use_validators_transform_recheck_and_redaction() { let mut config = item(true); config.transform_js = source.into(); config.validate_js = validator.map(Into::into); - let i = c.create_item(config, &caller, c.unlocked().unwrap()).unwrap(); - let secret = "SECRET_SENTINEL_19"; - c.set_field(&i.id, &i.fields[0].field_id, secret, &caller, c.unlocked().unwrap()) + let i = c + .create_item(config, &caller, c.unlocked().unwrap()) .unwrap(); + let secret = "SECRET_SENTINEL_19"; + c.set_field( + &i.id, + &i.fields[0].field_id, + secret, + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); let result = c.inject(parts("api.example"), &caller, &Fake); if let Some(expected) = expected { let error = result.err().unwrap(); @@ -175,9 +196,17 @@ fn atomic_budget_and_decision_notification() { let dir = tempfile::tempdir().unwrap(); let c = std::sync::Arc::new(Cred::open(dir.path()).unwrap()); let caller = caller("root"); - let i = c.create_item(item(false), &caller, c.unlocked().unwrap()).unwrap(); - c.set_field(&i.id, &i.fields[0].field_id, "opaque", &caller, c.unlocked().unwrap()) + let i = c + .create_item(item(false), &caller, c.unlocked().unwrap()) .unwrap(); + c.set_field( + &i.id, + &i.fields[0].field_id, + "opaque", + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); c.grant_create( Grant { id: String::new(), @@ -215,10 +244,21 @@ fn atomic_budget_and_decision_notification() { ); let id = c.request_list().unwrap()[0].id.clone(); let mut receiver = c.subscribe(); - c.deny(&id, sausage::cred::webauthn::Decision::Deny, c.unlocked().unwrap()).unwrap(); + c.deny( + &id, + sausage::cred::webauthn::Decision::Deny, + c.unlocked().unwrap(), + ) + .unwrap(); assert_eq!(receiver.try_recv().unwrap(), id); assert_eq!( - c.deny(&id, sausage::cred::webauthn::Decision::Deny, c.unlocked().unwrap()).unwrap_err().0, + c.deny( + &id, + sausage::cred::webauthn::Decision::Deny, + c.unlocked().unwrap() + ) + .unwrap_err() + .0, "already_decided" ); } @@ -230,7 +270,9 @@ fn key_and_secret_persist() { let caller = caller("root"); let mut config = item(true); config.transform_js = "inject".into(); - let i = c.create_item(config, &caller, c.unlocked().unwrap()).unwrap(); + let i = c + .create_item(config, &caller, c.unlocked().unwrap()) + .unwrap(); c.set_field( &i.id, &i.fields[0].field_id, diff --git a/host/tests/cred_accounting.rs b/host/tests/cred_accounting.rs new file mode 100644 index 0000000..3ee10cb --- /dev/null +++ b/host/tests/cred_accounting.rs @@ -0,0 +1,111 @@ +//! Reservations commit their audit row atomically. Unrelated rows do not enter the hot path. +use sausage::cred::{ + grants::Grant, + inject::Outcome, + items::Item, + script::{self, Limits, Script}, + *, +}; +struct Noop; +impl Script for Noop { + fn evaluate( + &self, + _: &str, + _: &str, + _: Option<&str>, + _: Limits, + ) -> std::result::Result { + Ok("{}".into()) + } +} +fn config(name: &str, host: &str) -> Item { + serde_json::from_value(serde_json::json!({"name":name,"rules":[{"scheme":"https","hosts":[host],"path_prefixes":["/"],"methods":null}],"validate_js":null,"transform_js":"","fields":[]})).unwrap() +} +fn fixture() -> (tempfile::TempDir, Cred, Caller, Item, Grant) { + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller { + program: "/bin/test.wasm".into(), + pid: 1, + conversations: vec!["root".into()], + }; + let item = c + .create_item( + config("test", "api.example"), + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + let grant = c + .grant_create( + Grant { + id: String::new(), + items: vec![item.id.clone()], + subject: types::Subject::Conversation("root".into()), + exp: None, + max_uses: Some(1), + uses: 0, + revoked: false, + validator: None, + note: None, + }, + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + (dir, c, caller, item, grant) +} +fn parts() -> http::request::Parts { + http::Request::get("https://api.example/") + .body(()) + .unwrap() + .into_parts() + .0 +} +#[test] +fn audit_failure_rolls_back_reservation() { + let (dir, c, caller, _item, grant) = fixture(); + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + db.execute_batch("CREATE TRIGGER fail_fetch_audit BEFORE INSERT ON audit WHEN NEW.event LIKE 'fetch.%' BEGIN SELECT RAISE(ABORT,'forced'); END;").unwrap(); + assert!(c.inject(parts(), &caller, &Noop).is_err()); + assert_eq!(c.grant_status(&grant.id).unwrap().uses, 0); + db.execute_batch("DROP TRIGGER fail_fetch_audit").unwrap(); + assert!(matches!( + c.inject(parts(), &caller, &Noop).unwrap(), + Outcome::Forward(_) + )); + let rows = c.audit_list().unwrap(); + assert_eq!(rows.iter().filter(|r| r.event == "fetch.use").count(), 1); +} +#[test] +fn revoked_rows_are_filtered_before_deserialization() { + let (dir, c, caller, _item, _grant) = fixture(); + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + db.execute("INSERT INTO grants(id,items,subject,uses,revoked) VALUES('inactive','invalid-json','invalid-json',0,1)",[]).unwrap(); + assert!(matches!( + c.inject(parts(), &caller, &Noop).unwrap(), + Outcome::Forward(_) + )); +} +#[test] +fn unmatched_configs_are_not_read_during_injection() { + let (dir, c, caller, _item, _grant) = fixture(); + let other = c + .create_item( + config("other", "other.example"), + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + // An invalid JSON marker detects an unwanted read of an unrelated config. + db.execute( + "UPDATE items SET config='invalid-json' WHERE id=?", + [other.id], + ) + .unwrap(); + assert!(matches!( + c.inject(parts(), &caller, &Noop).unwrap(), + Outcome::Forward(_) + )); +} diff --git a/host/tests/cred_authorization.rs b/host/tests/cred_authorization.rs index f4f2c4e..2783cc6 100644 --- a/host/tests/cred_authorization.rs +++ b/host/tests/cred_authorization.rs @@ -1,34 +1,106 @@ //! Bootstrap proofs cannot survive registration. Typed overrides reject misspelled limits. -use sausage::cred::{*, items::{Item,Field}, requests::{GrantRequest,Overrides}, webauthn::{Decision,Unlocked}}; -fn fixture() -> (tempfile::TempDir,Cred,Caller,Item,String,Unlocked) { +use sausage::cred::{ + items::{Field, Item}, + requests::{GrantRequest, Overrides}, + webauthn::{Decision, Unlocked}, + *, +}; +fn fixture() -> (tempfile::TempDir, Cred, Caller, Item, String, Unlocked) { let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let proof = c.unlocked().unwrap(); - let caller = Caller { program:"/bin/test.wasm".into(),pid:1,conversations:vec!["root".into()] }; - let item = c.create_item(Item { id:String::new(),name:"test".into(),version:0,free_use:false,rules:vec![],validate_js:None,transform_js:String::new(),fields:vec![Field { field_id:String::new(),name:"secret".into(),public:false,value:None,needs_value:true,field_type:types::FieldType::Text,key_type:None }] },&caller,proof).unwrap(); - let id = c.file_request(&caller,"request",GrantRequest { items:vec![item.id.clone()],duration_secs:None,max_uses:None,validator:None }).unwrap(); + let caller = Caller { + program: "/bin/test.wasm".into(), + pid: 1, + conversations: vec!["root".into()], + }; + let item = c + .create_item( + Item { + id: String::new(), + name: "test".into(), + version: 0, + free_use: false, + rules: vec![], + validate_js: None, + transform_js: String::new(), + fields: vec![Field { + field_id: String::new(), + name: "secret".into(), + public: false, + value: None, + needs_value: true, + field_type: types::FieldType::Text, + key_type: None, + }], + }, + &caller, + proof, + ) + .unwrap(); + let id = c + .file_request( + &caller, + "request", + GrantRequest { + items: vec![item.id.clone()], + duration_secs: None, + max_uses: None, + validator: None, + }, + ) + .unwrap(); let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); - db.execute("INSERT INTO passkey_credentials VALUES('synthetic','test','{}')",[]).unwrap(); - (dir,c,caller,item,id,proof) + db.execute( + "INSERT INTO passkey_credentials VALUES('synthetic','test','{}')", + [], + ) + .unwrap(); + (dir, c, caller, item, id, proof) } #[test] fn registered_passkey_refuses_unlocked_approval() { - let (_dir,c,_caller,_item,id,proof) = fixture(); - assert!(c.approve(&id,Decision::Approve,Overrides::default(),proof).is_err()); - assert_eq!(c.request_list().unwrap()[0].state,"pending"); + let (_dir, c, _caller, _item, id, proof) = fixture(); + assert!( + c.approve(&id, Decision::Approve, Overrides::default(), proof) + .is_err() + ); + assert_eq!(c.request_list().unwrap()[0].state, "pending"); assert!(c.unlocked().is_err()); } #[test] fn registered_passkey_refuses_unlocked_denial() { - let (_dir,c,_caller,_item,id,proof) = fixture(); - assert!(c.deny(&id,Decision::Deny,proof).is_err()); + let (_dir, c, _caller, _item, id, proof) = fixture(); + assert!(c.deny(&id, Decision::Deny, proof).is_err()); } #[test] fn registered_passkey_refuses_direct_mutations() { - let (_dir,c,caller,item,_id,proof) = fixture(); - assert!(c.set_field(&item.id,&item.fields[0].field_id,"synthetic",&caller,proof).is_err()); - assert!(c.create_item(Item { name:"another".into(),..item },&caller,proof).is_err()); - assert!(c.revoke_subjects(&caller.conversations,&caller,proof).is_err()); + let (_dir, c, caller, item, _id, proof) = fixture(); + assert!( + c.set_field( + &item.id, + &item.fields[0].field_id, + "synthetic", + &caller, + proof + ) + .is_err() + ); + assert!( + c.create_item( + Item { + name: "another".into(), + ..item + }, + &caller, + proof + ) + .is_err() + ); + assert!( + c.revoke_subjects(&caller.conversations, &caller, proof) + .is_err() + ); } #[test] fn overrides_reject_unknown_fields() { diff --git a/host/tests/cred_challenges.rs b/host/tests/cred_challenges.rs index dca4358..c8098c3 100644 --- a/host/tests/cred_challenges.rs +++ b/host/tests/cred_challenges.rs @@ -6,21 +6,25 @@ use webauthn_rs::prelude::*; fn failed_response_preserves_challenge_and_oldest_challenge_is_evicted() -> anyhow::Result<()> { let db = rusqlite::Connection::open_in_memory()?; let origin = Url::parse("http://localhost:8000")?; - let mut host = Passkeys::new(&db,"localhost",origin.as_str())?; + let mut host = Passkeys::new(&db, "localhost", origin.as_str())?; let mut auth = WebauthnAuthenticator::new(SoftPasskey::new(true)); - let registration = host.start_registration("test".into(),None)?; - let response = auth.do_registration(origin.clone(),registration.options)?; - host.finish_registration(®istration.id,response)?; - let binding = Binding::Enrollment { label:"next".into() }; + let registration = host.start_registration("test".into(), None)?; + let response = auth.do_registration(origin.clone(), registration.options)?; + host.finish_registration(®istration.id, response)?; + let binding = Binding::Enrollment { + label: "next".into(), + }; let valid = host.start_assertion(binding.clone())?; let wrong = host.start_assertion(binding.clone())?; - let invalid_response = auth.do_authentication(origin.clone(),wrong.options)?; - assert!(host.finish_assertion(&valid.id,invalid_response).is_err()); - let response = auth.do_authentication(origin.clone(),valid.options)?; - host.finish_assertion(&valid.id,response)?; + let invalid_response = auth.do_authentication(origin.clone(), wrong.options)?; + assert!(host.finish_assertion(&valid.id, invalid_response).is_err()); + let response = auth.do_authentication(origin.clone(), valid.options)?; + host.finish_assertion(&valid.id, response)?; let oldest = host.start_assertion(binding.clone())?; - for _ in 0..32 { host.start_assertion(binding.clone())?; } - let response = auth.do_authentication(origin,oldest.options)?; - assert!(host.finish_assertion(&oldest.id,response).is_err()); + for _ in 0..32 { + host.start_assertion(binding.clone())?; + } + let response = auth.do_authentication(origin, oldest.options)?; + assert!(host.finish_assertion(&oldest.id, response).is_err()); Ok(()) } diff --git a/host/tests/cred_core.rs b/host/tests/cred_core.rs index 4c3115e..20061ee 100644 --- a/host/tests/cred_core.rs +++ b/host/tests/cred_core.rs @@ -96,8 +96,14 @@ fn rule_matching_table() { #[test] fn revisions_needs_value_and_rename_are_metadata_only() { let (_dir, c, caller, i) = fixture(); - c.set_field(&i.id, &i.fields[0].field_id, "opaque", &caller, c.unlocked().unwrap()) - .unwrap(); + c.set_field( + &i.id, + &i.fields[0].field_id, + "opaque", + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); let old = c.item_get(&i.id).unwrap(); assert_eq!(old.version, 2); assert!(!old.fields[0].needs_value); @@ -117,8 +123,13 @@ fn revisions_needs_value_and_rename_are_metadata_only() { ) .unwrap(); assert!(!c.edit_diff(&id).unwrap().discards_values); - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap(); + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); let current = c.item_get(&i.id).unwrap(); assert_eq!(current.version, 3); assert_eq!(current.fields[0].field_id, old.fields[0].field_id); @@ -139,12 +150,23 @@ fn stale_edits_leave_history_and_values_untouched() { }, ) .unwrap(); - c.set_field(&i.id, &i.fields[0].field_id, "opaque", &caller, c.unlocked().unwrap()) - .unwrap(); + c.set_field( + &i.id, + &i.fields[0].field_id, + "opaque", + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); assert_eq!( - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap_err() - .0, + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap() + ) + .unwrap_err() + .0, "stale" ); assert_eq!(c.request_list().unwrap()[0].state, "pending"); @@ -166,10 +188,16 @@ fn key_conflict_renewal_and_expiry() { c.file_request(&caller, "key", other).unwrap_err().0, "key_conflict" ); - c.deny(&id, sausage::cred::webauthn::Decision::Deny, c.unlocked().unwrap()).unwrap(); + c.deny( + &id, + sausage::cred::webauthn::Decision::Deny, + c.unlocked().unwrap(), + ) + .unwrap(); assert_eq!(c.file_request(&caller, "key", p.clone()).unwrap(), id); let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); - db.execute("UPDATE requests SET expires=0 WHERE id=?", [&id]).unwrap(); + db.execute("UPDATE requests SET expires=0 WHERE id=?", [&id]) + .unwrap(); let next = c.file_request(&caller, "key", p).unwrap(); assert_ne!(id, next); assert_eq!(c.request_decisions().unwrap().len(), 1); @@ -179,9 +207,14 @@ fn key_conflict_renewal_and_expiry() { assert_eq!(c.expire_requests().unwrap(), vec![next.clone()]); assert_eq!(notification.try_recv().unwrap(), next); assert_eq!( - c.approve(&next, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap_err() - .0, + c.approve( + &next, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap() + ) + .unwrap_err() + .0, "request_expired" ); assert!(c.grant_list().unwrap().is_empty()); @@ -190,16 +223,24 @@ fn key_conflict_renewal_and_expiry() { fn typed_values_and_secret_configuration_fail_without_writes() { let (_dir, c, caller, i) = fixture(); assert_eq!( - c.set_field(&i.id, &i.fields[0].field_id, "line\nbreak", &caller, c.unlocked().unwrap()) - .unwrap_err() - .0, + c.set_field( + &i.id, + &i.fields[0].field_id, + "line\nbreak", + &caller, + c.unlocked().unwrap() + ) + .unwrap_err() + .0, "invalid_value" ); assert_eq!(c.item_get(&i.id).unwrap().version, 1); let mut config = i.clone(); config.fields[0].value = Some("forbidden".into()); assert_eq!( - c.create_item(config, &caller, c.unlocked().unwrap()).unwrap_err().0, + c.create_item(config, &caller, c.unlocked().unwrap()) + .unwrap_err() + .0, "secret_field" ); assert_eq!(c.item_list().unwrap().len(), 1); diff --git a/host/tests/cred_edits.rs b/host/tests/cred_edits.rs index f9357d0..86d87b9 100644 --- a/host/tests/cred_edits.rs +++ b/host/tests/cred_edits.rs @@ -48,8 +48,13 @@ fn creation_key_generation_and_deletion_keep_secrets_out_of_history() { ) .unwrap(); assert!(c.item_list().unwrap().is_empty()); - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap(); + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); let item = c.item_list().unwrap().remove(0); assert!(!item.fields[0].needs_value); assert!(item.fields[0].value.is_none()); @@ -69,8 +74,13 @@ fn creation_key_generation_and_deletion_keep_secrets_out_of_history() { }, ) .unwrap(); - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap(); + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); assert!(c.item_list().unwrap().is_empty()); assert_eq!(c.item_versions(&item.id).unwrap().len(), 1); let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); @@ -89,8 +99,11 @@ fn operation_order_name_conflicts_and_stale_resolution() { pid: 3, conversations: vec!["root".into()], }; - let item = c.create_item(config("first"), &caller, c.unlocked().unwrap()).unwrap(); - c.create_item(config("taken"), &caller, c.unlocked().unwrap()).unwrap(); + let item = c + .create_item(config("first"), &caller, c.unlocked().unwrap()) + .unwrap(); + c.create_item(config("taken"), &caller, c.unlocked().unwrap()) + .unwrap(); let request = |change| OperationRequest { item: Some(item.id.clone()), base_version: Some(item.version), @@ -129,19 +142,35 @@ fn operation_order_name_conflicts_and_stale_resolution() { request(vec![Operation::SetFreeUse { enabled: true }]), ) .unwrap(); - c.approve(&other, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap(); + c.approve( + &other, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); assert!(c.edit_diff(&id).unwrap().stale); assert_eq!( - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap_err() - .0, + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap() + ) + .unwrap_err() + .0, "stale" ); - c.resolve_stale(&id, 2, &caller, c.unlocked().unwrap()).unwrap(); - assert!(!c.edit_diff(&id).unwrap().stale); - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) + c.resolve_stale(&id, 2, &caller, c.unlocked().unwrap()) .unwrap(); + assert!(!c.edit_diff(&id).unwrap().stale); + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); let current = c.item_get(&item.id).unwrap(); assert_eq!(current.name, "last"); assert!(current.free_use); @@ -167,7 +196,9 @@ fn field_removal_revert_and_public_visibility() { field_type: types::FieldType::Text, key_type: None, }); - let item = c.create_item(initial, &caller, c.unlocked().unwrap()).unwrap(); + let item = c + .create_item(initial, &caller, c.unlocked().unwrap()) + .unwrap(); c.set_field( &item.id, &item.fields[0].field_id, @@ -198,13 +229,23 @@ fn field_removal_revert_and_public_visibility() { ) .unwrap(); assert!(c.edit_diff(&id).unwrap().discards_values); - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap(); + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); let id = c .file_revert_request(&caller, "revert", &item.id, 3, 2) .unwrap(); - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap(); + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); let restored = c.item_get(&item.id).unwrap(); assert!(restored.fields[0].needs_value); assert_eq!(restored.fields[0].field_id, item.fields[0].field_id); @@ -253,14 +294,24 @@ fn decision_failure_rolls_back_every_write() { let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); db.execute_batch("CREATE TRIGGER fail_decision BEFORE UPDATE ON requests BEGIN SELECT RAISE(ABORT, 'forced'); END;").unwrap(); assert!( - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .is_err() + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap() + ) + .is_err() ); assert!(c.item_list().unwrap().is_empty()); assert!(c.audit_list().unwrap().is_empty()); assert_eq!(c.request_list().unwrap()[0].state, "pending"); db.execute_batch("DROP TRIGGER fail_decision;").unwrap(); - c.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), c.unlocked().unwrap()) - .unwrap(); + c.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); assert_eq!(c.item_list().unwrap().len(), 1); } diff --git a/host/tests/cred_grants.rs b/host/tests/cred_grants.rs index b90a321..c78c8f0 100644 --- a/host/tests/cred_grants.rs +++ b/host/tests/cred_grants.rs @@ -123,7 +123,9 @@ fn program_grant_covers_service_and_agent_but_not_another_program() { #[test] fn expiry_boundary_revoke_and_exhaustion() { let (dir, c, caller, i) = fixture(); - let g = c.grant_create(grant(&i), &caller, c.unlocked().unwrap()).unwrap(); + let g = c + .grant_create(grant(&i), &caller, c.unlocked().unwrap()) + .unwrap(); assert!(matches!( c.inject(parts(), &caller, &Fake).unwrap(), Outcome::Forward(_) @@ -136,7 +138,9 @@ fn expiry_boundary_revoke_and_exhaustion() { assert_eq!(c.grant_status(&g.id).unwrap().uses, 1); let mut unlimited = grant(&i); unlimited.max_uses = None; - let g = c.grant_create(unlimited, &caller, c.unlocked().unwrap()).unwrap(); + let g = c + .grant_create(unlimited, &caller, c.unlocked().unwrap()) + .unwrap(); let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); db.execute("UPDATE grants SET exp=0 WHERE id=?", [&g.id]) .unwrap(); @@ -155,13 +159,17 @@ fn reject_bad_issuance_without_rows() { let mut g = grant(&i); g.max_uses = Some(0); assert_eq!( - c.grant_create(g, &caller, c.unlocked().unwrap()).unwrap_err().0, + c.grant_create(g, &caller, c.unlocked().unwrap()) + .unwrap_err() + .0, "invalid_uses" ); let mut g = grant(&i); g.subject = types::Subject::Conversation(String::new()); assert_eq!( - c.grant_create(g, &caller, c.unlocked().unwrap()).unwrap_err().0, + c.grant_create(g, &caller, c.unlocked().unwrap()) + .unwrap_err() + .0, "invalid_subject" ); assert!(c.grant_list().unwrap().is_empty()); diff --git a/host/tests/cred_maintenance.rs b/host/tests/cred_maintenance.rs new file mode 100644 index 0000000..be16bb3 --- /dev/null +++ b/host/tests/cred_maintenance.rs @@ -0,0 +1,216 @@ +//! D57 retention preserves pending work and all versions. Revocation only removes access. +use sausage::cred::{ + edits::{Edit, Operation, OperationRequest}, + grants::Grant, + items::Item, + requests::{GrantRequest, Overrides}, + webauthn::Decision, + *, +}; +fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller { + program: "/bin/test.wasm".into(), + pid: 1, + conversations: vec!["root".into()], + }; + let item=c.create_item(serde_json::from_value(serde_json::json!({"name":"test","rules":[],"validate_js":null,"transform_js":"","fields":[]})).unwrap(),&caller,c.unlocked().unwrap()).unwrap(); + (dir, c, caller, item) +} +fn grant(item: &Item, subject: types::Subject) -> Grant { + Grant { + id: String::new(), + items: vec![item.id.clone()], + subject, + exp: None, + max_uses: None, + uses: 0, + revoked: false, + validator: None, + note: None, + } +} +fn request(item: &Item) -> GrantRequest { + GrantRequest { + items: vec![item.id.clone()], + duration_secs: None, + max_uses: None, + validator: None, + } +} +#[test] +fn prune_obeys_cutoffs_and_preserves_pending_live_and_versions() { + let (dir, c, caller, item) = fixture(); + let now = 200 * 86400; + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + let old = c.file_request(&caller, "old", request(&item)).unwrap(); + c.approve( + &old, + Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); + let expired = c.grant_list().unwrap()[0].id.clone(); + db.execute( + "UPDATE requests SET decided_at=? WHERE id=?", + rusqlite::params![now - 31 * 86400, old], + ) + .unwrap(); + db.execute( + "UPDATE grants SET exp=? WHERE id=?", + rusqlite::params![now - 31 * 86400, expired], + ) + .unwrap(); + let pending = c.file_request(&caller, "pending", request(&item)).unwrap(); + db.execute("UPDATE requests SET expires=0 WHERE id=?", [&pending]) + .unwrap(); + let edge = c.file_request(&caller, "edge", request(&item)).unwrap(); + c.deny(&edge, Decision::Deny, c.unlocked().unwrap()) + .unwrap(); + db.execute( + "UPDATE requests SET decided_at=? WHERE id=?", + rusqlite::params![now - 30 * 86400, edge], + ) + .unwrap(); + let live = c + .grant_create( + grant(&item, types::Subject::Conversation("root".into())), + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + let revoked = c + .grant_create( + grant(&item, types::Subject::Conversation("root".into())), + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + c.revoke_grant(&revoked.id, &caller).unwrap(); + db.execute( + "UPDATE grants SET revoked_at=? WHERE id=?", + rusqlite::params![now - 31 * 86400, revoked.id], + ) + .unwrap(); + let protected = c + .grant_create( + grant(&item, types::Subject::Conversation("root".into())), + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + db.execute( + "UPDATE grants SET exp=? WHERE id=?", + rusqlite::params![now - 31 * 86400, protected.id], + ) + .unwrap(); + c.file_operation_request( + &caller, + "protected", + OperationRequest { + item: None, + base_version: None, + change: vec![Operation::GrantRevoke { + target: protected.id.clone(), + }], + }, + ) + .unwrap(); + let mut config = item.clone(); + config.name = "renamed".into(); + let edit = c + .file_edit_request( + &caller, + "edit", + Edit { + item: item.id.clone(), + base_version: item.version, + config, + }, + ) + .unwrap(); + c.approve( + &edit, + Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); + db.execute("UPDATE versions SET created=0", []).unwrap(); + db.execute( + "INSERT INTO audit(time,event,pid,program) VALUES(?,'old-marker',1,'test')", + [now - 91 * 86400], + ) + .unwrap(); + db.execute( + "INSERT INTO audit(time,event,pid,program) VALUES(?,'edge-marker',1,'test')", + [now - 90 * 86400], + ) + .unwrap(); + c.prune(now).unwrap(); + let requests = c.request_list().unwrap(); + assert!(!requests.iter().any(|r| r.id == old)); + assert!(requests.iter().any(|r| r.id == pending)); + assert!(requests.iter().any(|r| r.id == edge)); + let grants = c.grant_list().unwrap(); + assert!(!grants.iter().any(|g| g.id == expired || g.id == revoked.id)); + assert!(grants.iter().any(|g| g.id == live.id)); + assert!(grants.iter().any(|g| g.id == protected.id)); + let audit = c.audit_list().unwrap(); + assert!(!audit.iter().any(|r| r.event == "old-marker")); + assert!(audit.iter().any(|r| r.event == "edge-marker")); + assert_eq!(c.item_versions(&item.id).unwrap().len(), 1); +} +#[test] +fn revoke_ids_programs_and_full_subtrees_without_widening_access() { + let (dir, c, caller, item) = fixture(); + let root = c + .grant_create( + grant(&item, types::Subject::Conversation("root".into())), + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + let child = c + .grant_create( + grant(&item, types::Subject::Conversation("child".into())), + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + c.revoke_subjects( + &["root".into(), "child".into()], + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + assert!(c.grant_status(&root.id).unwrap().revoked); + assert!(c.grant_status(&child.id).unwrap().revoked); + let program = c + .grant_create( + grant(&item, types::Subject::Program("/bin/service.wasm".into())), + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + let other = c + .grant_create( + grant(&item, types::Subject::Program("/bin/other.wasm".into())), + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + db.execute( + "INSERT INTO passkey_credentials VALUES('synthetic','test','{}')", + [], + ) + .unwrap(); + c.revoke_program("/bin/service.wasm", &caller).unwrap(); + assert!(c.grant_status(&program.id).unwrap().revoked); + assert!(!c.grant_status(&other.id).unwrap().revoked); + c.revoke_grant(&other.id, &caller).unwrap(); + assert!(c.grant_status(&other.id).unwrap().revoked); +} diff --git a/host/tests/cred_policy.rs b/host/tests/cred_policy.rs index 38ed48c..195e232 100644 --- a/host/tests/cred_policy.rs +++ b/host/tests/cred_policy.rs @@ -1,44 +1,150 @@ -//! Approval policy regressions for explicit grant operations and denied request replay. -use sausage::cred::{*, edits::{Operation, OperationRequest}, grants::Grant, items::Item, requests::{GrantRequest, Overrides}}; +//! Explicit grant approvals honor their limits. Denials suppress duplicate approval prompts. +use sausage::cred::{ + edits::{Operation, OperationRequest}, + grants::Grant, + items::Item, + requests::{GrantRequest, Overrides}, + webauthn::Decision, + *, +}; +fn now() -> i64 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64 +} fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); - let caller = Caller { program:"/bin/test.wasm".into(), pid:1, conversations:vec!["root".into()] }; - let item = c.create_item(serde_json::from_value(serde_json::json!({"name":"test","rules":[],"validate_js":null,"transform_js":"","fields":[]})).unwrap(), &caller, "test").unwrap(); - (dir,c,caller,item) + let caller = Caller { + program: "/bin/test.wasm".into(), + pid: 1, + conversations: vec!["root".into()], + }; + let item = c.create_item(serde_json::from_value(serde_json::json!({"name":"test","rules":[],"validate_js":null,"transform_js":"","fields":[]})).unwrap(),&caller,c.unlocked().unwrap()).unwrap(); + (dir, c, caller, item) } fn grant(item: &Item) -> Grant { - Grant { id:String::new(), items:vec![item.id.clone()], subject:types::Subject::Conversation("root".into()), exp:None, max_uses:None, uses:0, revoked:false, validator:None, note:None } + Grant { + id: String::new(), + items: vec![item.id.clone()], + subject: types::Subject::Conversation("root".into()), + exp: None, + max_uses: None, + uses: 0, + revoked: false, + validator: None, + note: None, + } } fn operation(c: &Cred, caller: &Caller, key: &str, op: Operation) -> String { - c.file_operation_request(caller, key, OperationRequest { item:None, base_version:None, change:vec![op] }).unwrap() + c.file_operation_request( + caller, + key, + OperationRequest { + item: None, + base_version: None, + change: vec![op], + }, + ) + .unwrap() } #[test] fn grant_operations_apply_overrides_defaults_and_replay_liveness() { - let (_dir,c,caller,item) = fixture(); - let op = Operation::GrantCreate { grant:grant(&item) }; - let id = operation(&c,&caller,"grant",op.clone()); - c.approve(&id,"allow",Overrides { duration_secs:Some(120), max_uses:Some(1), validator:Some("true".into()), unlimited:false },None).unwrap(); + let (_dir, c, caller, item) = fixture(); + let op = Operation::GrantCreate { + grant: grant(&item), + }; + let id = operation(&c, &caller, "grant", op.clone()); + let before = now(); + c.approve( + &id, + Decision::Approve, + Overrides { + duration_secs: Some(120), + max_uses: Some(1), + validator: Some("true".into()), + unlimited: false, + }, + c.unlocked().unwrap(), + ) + .unwrap(); let g = c.grant_list().unwrap().pop().unwrap(); - let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as i64; - assert!(g.exp.is_some_and(|e| (now+115..=now+120).contains(&e))); - assert_eq!(g.max_uses,Some(1)); - assert_eq!(g.validator.as_deref(),Some("true")); - let revoke = operation(&c,&caller,"revoke",Operation::GrantRevoke { target:g.id }); - assert!(c.approve(&revoke,"allow",Overrides { duration_secs:Some(1), ..Default::default() },None).is_err()); - c.approve(&revoke,"allow",Overrides::default(),None).unwrap(); - assert_ne!(operation(&c,&caller,"grant",op),id); - let id = operation(&c,&caller,"default",Operation::GrantCreate { grant:grant(&item) }); - c.approve(&id,"allow",Overrides::default(),None).unwrap(); - assert!(c.grant_list().unwrap().last().unwrap().exp.is_some_and(|e| (now+3595..=now+3605).contains(&e))); + assert!( + g.exp + .is_some_and(|e| (before + 120..=now() + 120).contains(&e)) + ); + assert_eq!(g.max_uses, Some(1)); + assert_eq!(g.validator.as_deref(), Some("true")); + let revoke = operation( + &c, + &caller, + "revoke", + Operation::GrantRevoke { target: g.id }, + ); + assert!( + c.approve( + &revoke, + Decision::Approve, + Overrides { + duration_secs: Some(1), + ..Default::default() + }, + c.unlocked().unwrap() + ) + .is_err() + ); + c.approve( + &revoke, + Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); + assert_ne!(operation(&c, &caller, "grant", op), id); + let id = operation( + &c, + &caller, + "default", + Operation::GrantCreate { + grant: grant(&item), + }, + ); + let before = now(); + c.approve( + &id, + Decision::Approve, + Overrides::default(), + c.unlocked().unwrap(), + ) + .unwrap(); + assert!( + c.grant_list() + .unwrap() + .last() + .unwrap() + .exp + .is_some_and(|e| (before + 3600..=now() + 3600).contains(&e)) + ); } #[test] fn denial_replays_until_expiry_and_requester_duration_is_capped() { - let (_dir,c,caller,item) = fixture(); - let request = GrantRequest { items:vec![item.id], duration_secs:Some(86401), max_uses:None, validator:None }; - assert!(c.file_request(&caller,"too-long",request.clone()).is_err()); - let request = GrantRequest { duration_secs:None, ..request }; - let id = c.file_request(&caller,"denied",request.clone()).unwrap(); - c.deny(&id,"no",None).unwrap(); - assert_eq!(c.file_request(&caller,"denied",request).unwrap(),id); + let (_dir, c, caller, item) = fixture(); + let request = GrantRequest { + items: vec![item.id], + duration_secs: Some(86401), + max_uses: None, + validator: None, + }; + assert!( + c.file_request(&caller, "too-long", request.clone()) + .is_err() + ); + let request = GrantRequest { + duration_secs: None, + ..request + }; + let id = c.file_request(&caller, "denied", request.clone()).unwrap(); + c.deny(&id, Decision::Deny, c.unlocked().unwrap()).unwrap(); + assert_eq!(c.file_request(&caller, "denied", request).unwrap(), id); } diff --git a/host/tests/cred_presentation.rs b/host/tests/cred_presentation.rs index 881d8a5..8ef670e 100644 --- a/host/tests/cred_presentation.rs +++ b/host/tests/cred_presentation.rs @@ -1,16 +1,88 @@ //! Approval text exposes public policy and rejects deceptive display controls. -use sausage::cred::{edits::Operation, items::Item, summary::operation_summary}; +use sausage::cred::{ + Caller, Cred, + edits::{Edit, Operation, OperationRequest}, + items::Item, + summary::operation_summary, +}; #[test] fn summaries_show_public_values_rules_free_use_and_wildcard_risk() { let item: Item = serde_json::from_value(serde_json::json!({"name":"test","free_use":true,"rules":[{"scheme":"https","hosts":["*.com","api.example"],"port":8443,"path_prefixes":["/"],"methods":null}],"validate_js":null,"transform_js":"","fields":[]})).unwrap(); - let text = operation_summary(&Operation::CreateItem { config:item }); - for part in ["without a grant","*.com","api.example","8443","wildcard"] { assert!(text.contains(part)); } - let text = operation_summary(&Operation::SetFieldValue { field:"public-id".into(), value:"public-value".into() }); + let text = operation_summary(&Operation::CreateItem { config: item }); + for part in [ + "without a grant", + "*.com", + "api.example", + "8443", + "wildcard", + ] { + assert!(text.contains(part)); + } + let text = operation_summary(&Operation::SetFieldValue { + field: "public-id".into(), + value: "public-value".into(), + }); assert!(text.contains("public-id")); assert!(text.contains("public-value")); } #[test] +fn diffs_report_rule_overlaps_for_edits_and_creation() { + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller::default(); + let mut item:Item=serde_json::from_value(serde_json::json!({"name":"first","rules":[{"scheme":"https","hosts":["*.example"],"path_prefixes":["/"],"methods":null}],"validate_js":null,"transform_js":"","fields":[]})).unwrap(); + let first = c + .create_item(item.clone(), &caller, c.unlocked().unwrap()) + .unwrap(); + item.name = "second".into(); + item.rules[0].hosts = vec!["api.example".into()]; + let create = c + .file_operation_request( + &caller, + "create", + OperationRequest { + item: None, + base_version: None, + change: vec![Operation::CreateItem { + config: item.clone(), + }], + }, + ) + .unwrap(); + assert!( + c.request_diff(&create).unwrap()["overlapping_items"] + .as_array() + .unwrap() + .iter() + .any(|v| v == &first.id) + ); + let second = c.create_item(item, &caller, c.unlocked().unwrap()).unwrap(); + let mut config = second.clone(); + config.name = "edited".into(); + let edit = c + .file_edit_request( + &caller, + "edit", + Edit { + item: second.id, + base_version: second.version, + config, + }, + ) + .unwrap(); + assert!( + c.edit_diff(&edit) + .unwrap() + .overlapping_items + .contains(&first.id) + ); +} +#[test] fn summaries_remove_bidi_and_zero_width_controls() { - let text = operation_summary(&Operation::SetName { name:"a\u{202e}b\u{2066}c\u{200b}d\u{200d}e\u{feff}".into() }); - for c in ['\u{202e}','\u{2066}','\u{200b}','\u{200d}','\u{feff}'] { assert!(!text.contains(c)); } + let text = operation_summary(&Operation::SetName { + name: "a\u{202e}b\u{2066}c\u{200b}d\u{200d}e\u{feff}".into(), + }); + for c in ['\u{202e}', '\u{2066}', '\u{200b}', '\u{200d}', '\u{feff}'] { + assert!(!text.contains(c)); + } } diff --git a/host/tests/cred_proofs.rs b/host/tests/cred_proofs.rs new file mode 100644 index 0000000..26bedc9 --- /dev/null +++ b/host/tests/cred_proofs.rs @@ -0,0 +1,259 @@ +//! Real assertions bind decisions, current payloads, and the exact encrypted field input. +use sausage::cred::{ + edits::Edit, + items::{Field, FieldInput, FieldValue, Item}, + requests::{GrantRequest, Overrides}, + webauthn::{Binding, Decision, Mutation, Passkeys}, + *, +}; +use webauthn_authenticator_rs::{WebauthnAuthenticator, softpasskey::SoftPasskey}; +use webauthn_rs::prelude::Url; +fn fixture() -> (tempfile::TempDir, Cred, Caller, Item) { + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller { + program: "/bin/test.wasm".into(), + pid: 1, + conversations: vec!["root".into()], + }; + let item = c + .create_item( + Item { + id: String::new(), + name: "test".into(), + version: 0, + free_use: false, + rules: vec![], + validate_js: None, + transform_js: String::new(), + fields: vec![Field { + field_id: String::new(), + name: "secret".into(), + public: false, + value: None, + needs_value: true, + field_type: types::FieldType::Text, + key_type: None, + }], + }, + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + (dir, c, caller, item) +} +fn register(host: &mut Passkeys<'_>, auth: &mut WebauthnAuthenticator) { + let start = host.start_registration("test".into(), None).unwrap(); + let response = auth + .do_registration(Url::parse("http://localhost:8000").unwrap(), start.options) + .unwrap(); + host.finish_registration(&start.id, response).unwrap(); +} +fn proof( + host: &mut Passkeys<'_>, + auth: &mut WebauthnAuthenticator, + binding: Binding, +) -> webauthn::Verified { + let start = host.start_assertion(binding).unwrap(); + let response = auth + .do_authentication(Url::parse("http://localhost:8000").unwrap(), start.options) + .unwrap(); + host.finish_assertion(&start.id, response).unwrap() +} +#[test] +fn verified_decisions_compare_choice_overrides_and_request() { + let (dir, c, caller, item) = fixture(); + let request = GrantRequest { + items: vec![item.id], + duration_secs: None, + max_uses: None, + validator: None, + }; + let a = c.file_request(&caller, "a", request.clone()).unwrap(); + let b = c.file_request(&caller, "b", request).unwrap(); + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + let mut host = Passkeys::new(&db, "localhost", "http://localhost:8000").unwrap(); + let mut auth = WebauthnAuthenticator::new(SoftPasskey::new(true)); + register(&mut host, &mut auth); + for binding in [ + c.decision_binding(&a, Decision::Deny, Overrides::default()) + .unwrap(), + c.decision_binding( + &a, + Decision::Approve, + Overrides { + max_uses: Some(1), + ..Default::default() + }, + ) + .unwrap(), + c.decision_binding(&b, Decision::Approve, Overrides::default()) + .unwrap(), + ] { + let p = proof(&mut host, &mut auth, binding); + assert_eq!( + c.approve(&a, Decision::Approve, Overrides::default(), p) + .unwrap_err() + .0, + "binding_mismatch" + ); + } + assert_eq!(c.request_list().unwrap()[0].state, "pending"); + let p = proof( + &mut host, + &mut auth, + c.decision_binding(&a, Decision::Approve, Overrides::default()) + .unwrap(), + ); + c.approve(&a, Decision::Approve, Overrides::default(), p) + .unwrap(); + assert!( + c.audit_list() + .unwrap() + .iter() + .any(|r| r.event == "approved" && r.approver.is_some()) + ); +} +#[test] +fn stale_resolution_invalidates_review_proof_and_audits_caller() { + let (dir, c, caller, item) = fixture(); + let mut config = item.clone(); + config.name = "edited".into(); + let id = c + .file_edit_request( + &caller, + "edit", + Edit { + item: item.id.clone(), + base_version: item.version, + config, + }, + ) + .unwrap(); + let binding = c + .decision_binding(&id, Decision::Approve, Overrides::default()) + .unwrap(); + c.set_field( + &item.id, + &item.fields[0].field_id, + "synthetic", + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + let version = c.item_get(&item.id).unwrap().version; + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + let mut host = Passkeys::new(&db, "localhost", "http://localhost:8000").unwrap(); + let mut auth = WebauthnAuthenticator::new(SoftPasskey::new(true)); + register(&mut host, &mut auth); + let reviewed = proof(&mut host, &mut auth, binding); + let resolve = proof( + &mut host, + &mut auth, + Binding::mutation( + Mutation::ResolveStale, + &serde_json::json!({"request_id":id,"base_version":version}), + ) + .unwrap(), + ); + let reviewer = Caller { + pid: 77, + program: "/bin/review.wasm".into(), + conversations: vec!["review".into()], + }; + c.resolve_stale(&id, version, &reviewer, resolve).unwrap(); + assert_eq!( + c.approve(&id, Decision::Approve, Overrides::default(), reviewed) + .unwrap_err() + .0, + "binding_mismatch" + ); + assert!( + c.audit_list() + .unwrap() + .iter() + .any(|r| r.event == "request.resolve_stale" + && r.pid == 77 + && r.payload_sha256.is_some()) + ); +} +fn envelope(key: &entry::EntryKey) -> entry::Envelope { + use aes_gcm::{Aes256Gcm, KeyInit, Nonce, aead::Aead}; + use p256::{PublicKey, SecretKey, ecdh::diffie_hellman, elliptic_curve::sec1::ToEncodedPoint}; + let secret = SecretKey::random(&mut p256::elliptic_curve::rand_core::OsRng); + let peer = PublicKey::from_sec1_bytes(&key.public_key()).unwrap(); + let shared = diffie_hellman(secret.to_nonzero_scalar(), peer.as_affine()); + let mut aes = [0u8; 32]; + hkdf::Hkdf::::new(None, shared.raw_secret_bytes()) + .expand(b"sausage/secret-entry/v1", &mut aes) + .unwrap(); + let iv = [1u8; 12]; + let ciphertext = Aes256Gcm::new_from_slice(&aes) + .unwrap() + .encrypt(Nonce::from_slice(&iv), b"synthetic".as_slice()) + .unwrap(); + entry::Envelope { + ephemeral_public_key: secret + .public_key() + .to_encoded_point(false) + .as_bytes() + .to_vec(), + iv, + ciphertext, + } +} +#[test] +fn secret_entry_binds_actual_envelope_target_and_metadata() { + let (dir, c, caller, item) = fixture(); + let key = entry::EntryKey::open(&dir.path().join("entry.key")).unwrap(); + let a = envelope(&key); + let b = envelope(&key); + let field = &item.fields[0].field_id; + let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); + let mut host = Passkeys::new(&db, "localhost", "http://localhost:8000").unwrap(); + let mut auth = WebauthnAuthenticator::new(SoftPasskey::new(true)); + register(&mut host, &mut auth); + let binding = Binding::SecretEntry { + item: item.id.clone(), + field: field.clone(), + ciphertext_sha256: a.sha256(), + field_type: Some(types::FieldType::Note), + key_type: None, + }; + for (target, env, kind) in [ + ("wrong-field", &a, types::FieldType::Note), + (field.as_str(), &b, types::FieldType::Note), + (field.as_str(), &a, types::FieldType::Text), + ] { + let p = proof(&mut host, &mut auth, binding.clone()); + let input = FieldInput { + value: FieldValue::Encrypted { + key: &key, + envelope: env, + }, + field_type: Some(kind), + key_type: None, + }; + assert_eq!( + c.set_field_input(&item.id, target, &input, &caller, p) + .unwrap_err() + .0, + "binding_mismatch" + ); + } + assert!(c.item_get(&item.id).unwrap().fields[0].needs_value); + let p = proof(&mut host, &mut auth, binding); + let input = FieldInput { + value: FieldValue::Encrypted { + key: &key, + envelope: &a, + }, + field_type: Some(types::FieldType::Note), + key_type: None, + }; + c.set_field_input(&item.id, field, &input, &caller, p) + .unwrap(); + let current = c.item_get(&item.id).unwrap(); + assert!(!current.fields[0].needs_value); + assert_eq!(current.fields[0].field_type, types::FieldType::Note); +} diff --git a/host/tests/cred_regressions.rs b/host/tests/cred_regressions.rs index de824ad..52e7d6a 100644 --- a/host/tests/cred_regressions.rs +++ b/host/tests/cred_regressions.rs @@ -102,22 +102,38 @@ fn missing_values_and_wrong_master_spend_nothing() { ); assert_eq!(cred.grant_status(&grant.id).unwrap().uses, 0); for field in &item.fields { - cred.set_field(&item.id, &field.field_id, "opaque", &caller, cred.unlocked().unwrap()) - .unwrap(); + cred.set_field( + &item.id, + &field.field_id, + "opaque", + &caller, + cred.unlocked().unwrap(), + ) + .unwrap(); } drop(cred); std::fs::write(dir.path().join("cred.key"), [7u8; 32]).unwrap(); assert!(Cred::open(dir.path()).is_err()); let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); - let uses: i64 = db.query_row("SELECT uses FROM grants WHERE id=?", [&grant.id], |r| r.get(0)).unwrap(); + let uses: i64 = db + .query_row("SELECT uses FROM grants WHERE id=?", [&grant.id], |r| { + r.get(0) + }) + .unwrap(); assert_eq!(uses, 0); } #[test] fn field_name_swaps_preserve_ciphertexts_and_failed_edits_roll_back() { let (dir, cred, caller, item) = fixture(); for field in &item.fields { - cred.set_field(&item.id, &field.field_id, "opaque", &caller, cred.unlocked().unwrap()) - .unwrap(); + cred.set_field( + &item.id, + &field.field_id, + "opaque", + &caller, + cred.unlocked().unwrap(), + ) + .unwrap(); } let db = rusqlite::Connection::open(dir.path().join("cred.sqlite")).unwrap(); let cipher = || { @@ -145,8 +161,13 @@ fn field_name_swaps_preserve_ciphertexts_and_failed_edits_roll_back() { }, ) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); assert!(cipher() == before); let current = cred.item_get(&item.id).unwrap(); let mut config = current.clone(); @@ -166,8 +187,13 @@ fn field_name_swaps_preserve_ciphertexts_and_failed_edits_roll_back() { let audit = cred.audit_list().unwrap().len(); db.execute_batch("CREATE TRIGGER fail_decision BEFORE UPDATE ON requests BEGIN SELECT RAISE(ABORT,'forced'); END;").unwrap(); assert!( - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .is_err() + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap() + ) + .is_err() ); assert!(cipher() == before); assert_eq!(cred.item_get(&item.id).unwrap().version, current.version); @@ -178,8 +204,14 @@ fn field_name_swaps_preserve_ciphertexts_and_failed_edits_roll_back() { fn deleted_item_revert_preserves_identity_but_never_restores_secrets() { let (_dir, cred, caller, item) = fixture(); for field in &item.fields { - cred.set_field(&item.id, &field.field_id, "opaque", &caller, cred.unlocked().unwrap()) - .unwrap(); + cred.set_field( + &item.id, + &field.field_id, + "opaque", + &caller, + cred.unlocked().unwrap(), + ) + .unwrap(); } let current = cred.item_get(&item.id).unwrap(); let id = cred @@ -192,8 +224,13 @@ fn deleted_item_revert_preserves_identity_but_never_restores_secrets() { }, ) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); let id = cred .file_revert_request( &caller, @@ -203,8 +240,13 @@ fn deleted_item_revert_preserves_identity_but_never_restores_secrets() { current.version, ) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); let restored = cred.item_get(&item.id).unwrap(); assert_eq!(restored.id, item.id); assert_eq!(restored.version, current.version + 2); @@ -224,10 +266,22 @@ fn secret_entry_keeps_oauth_cardinality_and_rolls_back_ciphertext() { field_type: Some(types::FieldType::Oauth2RefreshToken), key_type: None, }; - cred.set_field_input(&item.id, &item.fields[0].field_id, &input, &caller, cred.unlocked().unwrap()) - .unwrap(); - cred.set_field(&item.id, &item.fields[1].field_id, "opaque", &caller, cred.unlocked().unwrap()) - .unwrap(); + cred.set_field_input( + &item.id, + &item.fields[0].field_id, + &input, + &caller, + cred.unlocked().unwrap(), + ) + .unwrap(); + cred.set_field( + &item.id, + &item.fields[1].field_id, + "opaque", + &caller, + cred.unlocked().unwrap(), + ) + .unwrap(); let current = cred.item_get(&item.id).unwrap(); let history = cred.item_versions(&item.id).unwrap().len(); let audit = cred.audit_list().unwrap().len(); @@ -242,10 +296,16 @@ fn secret_entry_keeps_oauth_cardinality_and_rolls_back_ciphertext() { }; let before = cipher(); assert_eq!( - cred.set_field_input(&item.id, &item.fields[1].field_id, &input, &caller, cred.unlocked().unwrap()) - .err() - .unwrap() - .0, + cred.set_field_input( + &item.id, + &item.fields[1].field_id, + &input, + &caller, + cred.unlocked().unwrap() + ) + .err() + .unwrap() + .0, "invalid_params" ); assert!(cipher() == before); @@ -270,15 +330,26 @@ fn typed_secret_entry_and_bundle_normalization() { }, ) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); let input = FieldInput { value: sausage::cred::items::FieldValue::Plain("two\nlines"), field_type: Some(types::FieldType::Note), key_type: None, }; - cred.set_field_input(&item.id, &item.fields[0].field_id, &input, &caller, cred.unlocked().unwrap()) - .unwrap(); + cred.set_field_input( + &item.id, + &item.fields[0].field_id, + &input, + &caller, + cred.unlocked().unwrap(), + ) + .unwrap(); let current = cred.item_get(&item.id).unwrap(); assert_eq!(current.fields[0].field_type, types::FieldType::Note); assert!(current.fields[0].key_type.is_none()); @@ -308,7 +379,7 @@ fn typed_secret_entry_and_bundle_normalization() { unlimited: true, ..Overrides::default() }, - None, + cred.unlocked().unwrap(), ) .unwrap(); let g = cred.grant_list().unwrap().remove(0); diff --git a/host/tests/cred_replay.rs b/host/tests/cred_replay.rs index 5b380b6..78025f0 100644 --- a/host/tests/cred_replay.rs +++ b/host/tests/cred_replay.rs @@ -53,8 +53,13 @@ fn approved_operations_and_deletes_replay() { let id = cred .file_operation_request(&caller, "edit", request.clone()) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); assert_eq!( cred.file_operation_request(&caller, "edit", request) .unwrap(), @@ -68,8 +73,13 @@ fn approved_operations_and_deletes_replay() { let id = cred .file_delete_request(&caller, "delete", delete.clone()) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); assert_eq!( cred.file_delete_request(&caller, "delete", delete).unwrap(), id @@ -88,8 +98,13 @@ fn approved_replacements_and_creations_replay() { let id = cred .file_edit_request(&caller, "replace", edit.clone()) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); assert_eq!( cred.file_edit_request(&caller, "replace", edit).unwrap(), id @@ -103,8 +118,13 @@ fn approved_replacements_and_creations_replay() { let id = cred .file_operation_request(&caller, "create", request.clone()) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); assert_eq!( cred.file_operation_request(&caller, "create", request) .unwrap(), @@ -143,12 +163,22 @@ fn grant_defaults_normalize_and_pending_requests_replay_after_deletion() { }, ) .unwrap(); - cred.approve(&delete, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &delete, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); assert_eq!(cred.file_request(&caller, "grant", payload).unwrap(), id); assert!( - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .is_err() + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap() + ) + .is_err() ); assert_eq!( cred.request_list() @@ -184,8 +214,13 @@ fn values_are_checked_at_each_public_operation() { }, ) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); let current = cred.item_get(&item.id).unwrap(); let field = current .fields @@ -221,8 +256,13 @@ fn values_are_checked_at_each_public_operation() { let id = cred .file_operation_request(&caller, "ordered", request) .unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); assert_eq!( cred.item_get(&item.id).unwrap().version, current.version + 1 @@ -271,23 +311,40 @@ fn secret_retyping_checks_each_operation_only_on_approval() { .contains("VALUE_SENTINEL") ); assert_eq!( - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .err() - .unwrap() - .0, + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap() + ) + .err() + .unwrap() + .0, "invalid_value" ); assert_eq!(cred.item_get(&item.id).unwrap().version, current.version); assert_eq!(cred.request_list().unwrap()[0].state, "pending"); let history = cred.item_versions(&item.id).unwrap().len(); - cred.set_field(&item.id, field, "single-line", &caller, cred.unlocked().unwrap()) - .unwrap(); + cred.set_field( + &item.id, + field, + "single-line", + &caller, + cred.unlocked().unwrap(), + ) + .unwrap(); let next = cred.item_get(&item.id).unwrap(); assert_eq!(next.version, current.version + 1); assert_eq!(cred.item_versions(&item.id).unwrap().len(), history + 1); - cred.resolve_stale(&id, next.version, &caller, cred.unlocked().unwrap()).unwrap(); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) + cred.resolve_stale(&id, next.version, &caller, cred.unlocked().unwrap()) .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); } #[test] fn stale_rebases_keep_original_keyed_intent() { @@ -302,17 +359,29 @@ fn stale_rebases_keep_original_keyed_intent() { let id = cred .file_operation_request(&caller, "rebase", request.clone()) .unwrap(); - cred.set_field(&item.id, &item.fields[0].field_id, "opaque", &caller, cred.unlocked().unwrap()) - .unwrap(); + cred.set_field( + &item.id, + &item.fields[0].field_id, + "opaque", + &caller, + cred.unlocked().unwrap(), + ) + .unwrap(); let current = cred.item_get(&item.id).unwrap(); - cred.resolve_stale(&id, current.version, &caller, cred.unlocked().unwrap()).unwrap(); + cred.resolve_stale(&id, current.version, &caller, cred.unlocked().unwrap()) + .unwrap(); assert_eq!( cred.file_operation_request(&caller, "rebase", request.clone()) .unwrap(), id ); - cred.approve(&id, sausage::cred::webauthn::Decision::Approve, Overrides::default(), cred.unlocked().unwrap()) - .unwrap(); + cred.approve( + &id, + sausage::cred::webauthn::Decision::Approve, + Overrides::default(), + cred.unlocked().unwrap(), + ) + .unwrap(); assert_eq!( cred.file_operation_request(&caller, "rebase", request) .unwrap(), diff --git a/host/tests/cred_security.rs b/host/tests/cred_security.rs index f924ce7..ab63353 100644 --- a/host/tests/cred_security.rs +++ b/host/tests/cred_security.rs @@ -1,53 +1,158 @@ //! Destination matching fails closed before and after a credential transform. -use sausage::cred::{*, inject::Outcome, items::Item, script::{self,Script,Limits}}; +use sausage::cred::{ + inject::Outcome, + items::Item, + script::{self, Limits, Script}, + *, +}; use serde_json::json; struct Transform(serde_json::Value); impl Script for Transform { - fn evaluate(&self,_:&str,_:&str,_:Option<&str>,_:Limits) -> std::result::Result { Ok(self.0.to_string()) } + fn evaluate( + &self, + _: &str, + _: &str, + _: Option<&str>, + _: Limits, + ) -> std::result::Result { + Ok(self.0.to_string()) + } } -fn config(host:&str,port:Option) -> Item { +fn config(host: &str, port: Option) -> Item { serde_json::from_value(json!({"name":"destination","free_use":true,"rules":[{"scheme":"https","hosts":[host],"port":port,"path_prefixes":["/allowed/"],"methods":null}],"validate_js":null,"transform_js":"transform","fields":[]})).unwrap() } -fn parts(uri:&str) -> http::request::Parts { http::Request::get(uri).body(()).unwrap().into_parts().0 } +fn parts(uri: &str) -> http::request::Parts { + http::Request::get(uri).body(()).unwrap().into_parts().0 +} #[test] fn ports_before_and_after_transform() { - let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); - c.create_item(config("api.example",None),&caller,c.unlocked().unwrap()).unwrap(); - let Outcome::Forward(p) = c.inject(parts("https://api.example:9999/allowed/"),&caller,&Transform(json!({"headers":[{"name":"x-injected","value":"synthetic"}]}))).unwrap() else { panic!("denied") }; + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller::default(); + c.create_item(config("api.example", None), &caller, c.unlocked().unwrap()) + .unwrap(); + let Outcome::Forward(p) = c + .inject( + parts("https://api.example:9999/allowed/"), + &caller, + &Transform(json!({"headers":[{"name":"x-injected","value":"synthetic"}]})), + ) + .unwrap() + else { + panic!("denied") + }; assert!(!p.headers.contains_key("x-injected")); - assert!(c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({"url":"https://api.example:9999/allowed/"}))).is_err()); + assert!( + c.inject( + parts("https://api.example/allowed/"), + &caller, + &Transform(json!({"url":"https://api.example:9999/allowed/"})) + ) + .is_err() + ); } #[test] fn local_rules_require_ports_and_ipv6_matches() { - let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); - for host in ["localhost","127.0.0.1","::1","169.254.1.2","fe80::1"] { assert!(c.create_item(config(host,None),&caller,c.unlocked().unwrap()).is_err()); } - c.create_item(config("::1",Some(8443)),&caller,c.unlocked().unwrap()).unwrap(); - let Outcome::Forward(p) = c.inject(parts("https://[::1]:8443/allowed/"),&caller,&Transform(json!({"headers":[{"name":"x-injected","value":"synthetic"}]}))).unwrap() else { panic!("denied") }; + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller::default(); + for host in ["localhost", "127.0.0.1", "::1", "169.254.1.2", "fe80::1"] { + assert!( + c.create_item(config(host, None), &caller, c.unlocked().unwrap()) + .is_err() + ); + } + c.create_item(config("::1", Some(8443)), &caller, c.unlocked().unwrap()) + .unwrap(); + let Outcome::Forward(p) = c + .inject( + parts("https://[::1]:8443/allowed/"), + &caller, + &Transform(json!({"headers":[{"name":"x-injected","value":"synthetic"}]})), + ) + .unwrap() + else { + panic!("denied") + }; assert!(p.headers.contains_key("x-injected")); } #[test] fn unsafe_paths_fail_before_and_after_transform() { - let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); - c.create_item(config("api.example",None),&caller,c.unlocked().unwrap()).unwrap(); - for tail in ["./x","../x","%2e/x","%2E/x","x%2fy","x%2Fy","x%5cy","x%5Cy","x\\y"] { + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller::default(); + c.create_item(config("api.example", None), &caller, c.unlocked().unwrap()) + .unwrap(); + for tail in [ + "./x", "../x", "%2e/x", "%2E/x", "x%2fy", "x%2Fy", "x%5cy", "x%5Cy", "x\\y", + ] { let url = format!("https://api.example/allowed/{tail}"); - assert!(c.inject(parts(&url),&caller,&Transform(json!({}))).is_err()); - assert!(c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({"url":url}))).is_err()); + assert!( + c.inject(parts(&url), &caller, &Transform(json!({}))) + .is_err() + ); + assert!( + c.inject( + parts("https://api.example/allowed/"), + &caller, + &Transform(json!({"url":url})) + ) + .is_err() + ); } } #[test] fn transformed_authority_and_sensitive_headers() { - let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); - c.create_item(config("api.example",None),&caller,c.unlocked().unwrap()).unwrap(); + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller::default(); + c.create_item(config("api.example", None), &caller, c.unlocked().unwrap()) + .unwrap(); let Outcome::Forward(p) = c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({"headers":[{"name":"host","value":"wrong.example"},{"name":"authorization","value":"synthetic"}]}))).unwrap() else { panic!("denied") }; - assert!(p.headers["authorization"].is_sensitive()); assert_eq!(p.headers["host"],"api.example"); - assert!(c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({"url":"https://user@api.example/allowed/"}))).is_err()); + assert!(p.headers["authorization"].is_sensitive()); + assert_eq!(p.headers["host"], "api.example"); + assert!( + c.inject( + parts("https://api.example/allowed/"), + &caller, + &Transform(json!({"url":"https://user@api.example/allowed/"})) + ) + .is_err() + ); } #[test] fn oauth2_items_fail_without_exposing_refresh_values() { - let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); let caller = Caller::default(); let mut item = config("api.example",None); - item.fields.push(items::Field { field_id:String::new(),name:"refresh".into(),public:false,value:None,needs_value:true,field_type:types::FieldType::Oauth2RefreshToken,key_type:None }); - let item = c.create_item(item,&caller,c.unlocked().unwrap()).unwrap(); - c.set_field(&item.id,&item.fields[0].field_id,"synthetic",&caller,c.unlocked().unwrap()).unwrap(); - assert_eq!(c.inject(parts("https://api.example/allowed/"),&caller,&Transform(json!({}))).err().unwrap().0,"oauth2_item"); + let dir = tempfile::tempdir().unwrap(); + let c = Cred::open(dir.path()).unwrap(); + let caller = Caller::default(); + let mut item = config("api.example", None); + item.fields.push(items::Field { + field_id: String::new(), + name: "refresh".into(), + public: false, + value: None, + needs_value: true, + field_type: types::FieldType::Oauth2RefreshToken, + key_type: None, + }); + let item = c.create_item(item, &caller, c.unlocked().unwrap()).unwrap(); + c.set_field( + &item.id, + &item.fields[0].field_id, + "synthetic", + &caller, + c.unlocked().unwrap(), + ) + .unwrap(); + assert_eq!( + c.inject( + parts("https://api.example/allowed/"), + &caller, + &Transform(json!({})) + ) + .err() + .unwrap() + .0, + "oauth2_item" + ); } diff --git a/host/tests/cred_storage.rs b/host/tests/cred_storage.rs index 5603155..668fa7f 100644 --- a/host/tests/cred_storage.rs +++ b/host/tests/cred_storage.rs @@ -1,11 +1,11 @@ //! Master-key startup checks use only temporary host storage and synthetic keys. -use sausage::cred::{Cred, Caller}; +use sausage::cred::{Caller, Cred}; use std::os::unix::fs::PermissionsExt; #[test] fn missing_key_in_populated_store_is_not_replaced() { let dir = tempfile::tempdir().unwrap(); let c = Cred::open(dir.path()).unwrap(); - c.create_item(serde_json::from_value(serde_json::json!({"name":"stored","rules":[],"validate_js":null,"transform_js":"","fields":[]})).unwrap(), &Caller::default(), "test").unwrap(); + c.create_item(serde_json::from_value(serde_json::json!({"name":"stored","rules":[],"validate_js":null,"transform_js":"","fields":[]})).unwrap(), &Caller::default(), c.unlocked().unwrap()).unwrap(); drop(c); std::fs::remove_file(dir.path().join("cred.key")).unwrap(); assert!(Cred::open(dir.path()).is_err()); @@ -15,7 +15,7 @@ fn missing_key_in_populated_store_is_not_replaced() { fn wrong_master_key_fails_at_open_even_without_secret_fields() { let dir = tempfile::tempdir().unwrap(); drop(Cred::open(dir.path()).unwrap()); - std::fs::write(dir.path().join("cred.key"), [7u8;32]).unwrap(); + std::fs::write(dir.path().join("cred.key"), [7u8; 32]).unwrap(); assert!(Cred::open(dir.path()).is_err()); } #[test] @@ -23,8 +23,11 @@ fn permissive_key_is_refused_and_new_host_directory_is_private() { let dir = tempfile::tempdir().unwrap(); let host = dir.path().join("host"); drop(Cred::open(&host).unwrap()); - assert_eq!(std::fs::metadata(&host).unwrap().permissions().mode() & 0o777, 0o700); + assert_eq!( + std::fs::metadata(&host).unwrap().permissions().mode() & 0o777, + 0o700 + ); let key = host.join("cred.key"); - std::fs::set_permissions(&key,std::fs::Permissions::from_mode(0o644)).unwrap(); + std::fs::set_permissions(&key, std::fs::Permissions::from_mode(0o644)).unwrap(); assert!(Cred::open(&host).is_err()); } diff --git a/host/tests/cred_webauthn.rs b/host/tests/cred_webauthn.rs index da078a0..925440d 100644 --- a/host/tests/cred_webauthn.rs +++ b/host/tests/cred_webauthn.rs @@ -1,14 +1,15 @@ //! Software-authenticator coverage for enrollment gates and bound assertions. use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD}; -use sausage::cred::webauthn::{Binding, Gate, Passkeys}; +use sausage::cred::webauthn::{Binding, Decision, Gate, Passkeys}; use webauthn_authenticator_rs::{WebauthnAuthenticator, softpasskey::SoftPasskey}; use webauthn_rs::prelude::*; fn binding() -> Binding { Binding::Decision { request_id: "request-1".into(), - decision: "approve".into(), - overrides: serde_json::json!({}), + decision: Decision::Approve, + overrides: sausage::cred::requests::Overrides::default(), + payload_sha256: "synthetic-payload".into(), } } @@ -44,7 +45,10 @@ fn enrollment_and_assertions() -> anyhow::Result<()> { let start = host.start_assertion(binding())?; let response = auth.do_authentication(origin.clone(), start.options)?; let replay = serde_json::to_value(&response)?; - assert_eq!(host.finish_assertion(&start.id, response)?.1, binding()); + assert_eq!( + host.finish_assertion(&start.id, response)?.binding(), + &binding() + ); assert!( host.finish_assertion(&start.id, serde_json::from_value(replay)?) .is_err() From 86c5d8a4e4432dd75075cc530ca1116af7de6098 Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 6 Nov 2026 22:22:49 +0000 Subject: [PATCH 09/12] cred: isolate scripts in WASI and move RSA signing to AWS-LC --- Cargo.lock | 2 + host/Cargo.toml | 2 + host/cred-script/Cargo.lock | 584 + host/cred-script/Cargo.toml | 19 + host/cred-script/README.md | 46 + host/cred-script/build.nu | 9 + host/cred-script/script.wasm | Bin 0 -> 1564223 bytes host/cred-script/src/lib.rs | 243 + host/cred-script/src/main.rs | 58 + host/cred-script/src/tests.rs | 196 + host/cred-script/vendor/PATCHES.md | 50 + .../llrt_utils_watts/.cargo_vcs_info.json | 7 + .../vendor/llrt_utils_watts/Cargo.lock | 879 + .../vendor/llrt_utils_watts/Cargo.toml | 74 + .../vendor/llrt_utils_watts/Cargo.toml.orig | 34 + .../vendor/llrt_utils_watts/LICENSE | 202 + .../vendor/llrt_utils_watts/src/any_of.rs | 298 + .../llrt_utils_watts/src/bytearray_buffer.rs | 226 + .../vendor/llrt_utils_watts/src/bytes.rs | 380 + .../vendor/llrt_utils_watts/src/class.rs | 77 + .../vendor/llrt_utils_watts/src/clone.rs | 487 + .../vendor/llrt_utils_watts/src/ctx.rs | 17 + .../vendor/llrt_utils_watts/src/error.rs | 23 + .../llrt_utils_watts/src/error_messages.rs | 3 + .../vendor/llrt_utils_watts/src/fs.rs | 103 + .../vendor/llrt_utils_watts/src/hash.rs | 8 + .../vendor/llrt_utils_watts/src/io.rs | 30 + .../vendor/llrt_utils_watts/src/latch.rs | 30 + .../vendor/llrt_utils_watts/src/lib.rs | 33 + .../vendor/llrt_utils_watts/src/macros.rs | 55 + .../vendor/llrt_utils_watts/src/mc_oneshot.rs | 118 + .../vendor/llrt_utils_watts/src/module.rs | 29 + .../vendor/llrt_utils_watts/src/object.rs | 176 + .../vendor/llrt_utils_watts/src/option.rs | 101 + .../llrt_utils_watts/src/primordials.rs | 159 + .../vendor/llrt_utils_watts/src/provider.rs | 24 + .../vendor/llrt_utils_watts/src/result.rs | 104 + .../vendor/llrt_utils_watts/src/reuse_list.rs | 337 + .../vendor/llrt_utils_watts/src/signals.rs | 149 + .../vendor/llrt_utils_watts/src/string.rs | 17 + .../vendor/llrt_utils_watts/src/sysinfo.rs | 13 + .../vendor/llrt_utils_watts/src/time.rs | 47 + .../vendor/rquickjs-sys/.cargo_vcs_info.json | 6 + .../vendor/rquickjs-sys/.gitignore | 1 + .../vendor/rquickjs-sys/Cargo.lock | 319 + .../vendor/rquickjs-sys/Cargo.toml | 68 + .../vendor/rquickjs-sys/Cargo.toml.orig | 48 + host/cred-script/vendor/rquickjs-sys/Makefile | 28 + .../cred-script/vendor/rquickjs-sys/README.md | 24 + host/cred-script/vendor/rquickjs-sys/build.rs | 372 + .../vendor/rquickjs-sys/quickjs.bind.h | 16 + .../rquickjs-sys/quickjs/.gitattributes | 4 + .../quickjs/.github/dependabot.yml | 7 + .../quickjs/.github/workflows/ci.yml | 780 + .../quickjs/.github/workflows/docs.yml | 49 + .../quickjs/.github/workflows/release.yml | 155 + .../quickjs/.github/workflows/test-docs.yml | 23 + .../quickjs/.github/workflows/tsan.yml | 32 + .../quickjs/.github/workflows/valgrind.yml | 33 + .../vendor/rquickjs-sys/quickjs/.gitignore | 14 + .../vendor/rquickjs-sys/quickjs/.gitmodules | 5 + .../rquickjs-sys/quickjs/CMakeLists.txt | 461 + .../vendor/rquickjs-sys/quickjs/LICENSE | 24 + .../vendor/rquickjs-sys/quickjs/Makefile | 147 + .../vendor/rquickjs-sys/quickjs/README.md | 24 + .../vendor/rquickjs-sys/quickjs/amalgam.js | 49 + .../vendor/rquickjs-sys/quickjs/api-test.c | 854 + .../quickjs/builtin-array-fromasync.h | 113 + .../quickjs/builtin-array-fromasync.js | 36 + .../vendor/rquickjs-sys/quickjs/ctest.c | 17 + .../vendor/rquickjs-sys/quickjs/cutils.c | 1342 + .../vendor/rquickjs-sys/quickjs/cutils.h | 660 + .../vendor/rquickjs-sys/quickjs/cxxtest.cc | 2 + .../rquickjs-sys/quickjs/docs/.gitignore | 20 + .../vendor/rquickjs-sys/quickjs/docs/.nvmrc | 1 + .../rquickjs-sys/quickjs/docs/babel.config.js | 3 + .../quickjs/docs/docs/building.md | 63 + .../rquickjs-sys/quickjs/docs/docs/cli.md | 130 + .../docs/docs/developer-guide/_category_.json | 7 + .../quickjs/docs/docs/developer-guide/api.md | 3 + .../docs/docs/developer-guide/internals.md | 117 + .../docs/docs/developer-guide/intro.md | 113 + .../rquickjs-sys/quickjs/docs/docs/diff.md | 68 + .../quickjs/docs/docs/es_features.md | 11 + .../quickjs/docs/docs/installation.md | 34 + .../rquickjs-sys/quickjs/docs/docs/intro.md | 33 + .../quickjs/docs/docs/projects.md | 44 + .../rquickjs-sys/quickjs/docs/docs/stdlib.md | 577 + .../quickjs/docs/docs/supported_platforms.md | 20 + .../quickjs/docs/docusaurus.config.js | 114 + .../quickjs/docs/package-lock.json | 14656 ++++ .../rquickjs-sys/quickjs/docs/package.json | 42 + .../rquickjs-sys/quickjs/docs/sidebars.js | 20 + .../quickjs/docs/src/css/custom.css | 30 + .../quickjs/docs/static/.nojekyll | 0 .../quickjs/docs/static/img/favicon.ico | Bin 0 -> 3626 bytes .../vendor/rquickjs-sys/quickjs/dtoa.c | 1619 + .../vendor/rquickjs-sys/quickjs/dtoa.h | 87 + .../rquickjs-sys/quickjs/examples/fib.c | 80 + .../quickjs/examples/fib_module.js | 10 + .../rquickjs-sys/quickjs/examples/hello.js | 1 + .../quickjs/examples/hello_module.js | 6 + .../rquickjs-sys/quickjs/examples/meson.build | 19 + .../quickjs/examples/pi_bigint.js | 118 + .../rquickjs-sys/quickjs/examples/point.c | 160 + .../rquickjs-sys/quickjs/examples/test_fib.js | 8 + .../quickjs/examples/test_point.js | 43 + .../vendor/rquickjs-sys/quickjs/fuzz.c | 22 + .../quickjs/gen/function_source.c | 80 + .../vendor/rquickjs-sys/quickjs/gen/hello.c | 52 + .../rquickjs-sys/quickjs/gen/hello_module.c | 106 + .../vendor/rquickjs-sys/quickjs/gen/repl.c | 3025 + .../rquickjs-sys/quickjs/gen/standalone.c | 323 + .../rquickjs-sys/quickjs/gen/test_fib.c | 80 + .../rquickjs-sys/quickjs/libregexp-opcode.h | 58 + .../vendor/rquickjs-sys/quickjs/libregexp.c | 2676 + .../vendor/rquickjs-sys/quickjs/libregexp.h | 97 + .../rquickjs-sys/quickjs/libunicode-table.h | 4707 ++ .../vendor/rquickjs-sys/quickjs/libunicode.c | 1746 + .../vendor/rquickjs-sys/quickjs/libunicode.h | 126 + .../vendor/rquickjs-sys/quickjs/list.h | 107 + .../vendor/rquickjs-sys/quickjs/meson.build | 635 + .../rquickjs-sys/quickjs/meson_options.txt | 6 + .../vendor/rquickjs-sys/quickjs/qjs.c | 748 + .../vendor/rquickjs-sys/quickjs/qjsc.c | 673 + .../rquickjs-sys/quickjs/quickjs-atom.h | 265 + .../rquickjs-sys/quickjs/quickjs-c-atomics.h | 54 + .../rquickjs-sys/quickjs/quickjs-libc.c | 4693 ++ .../rquickjs-sys/quickjs/quickjs-libc.h | 81 + .../rquickjs-sys/quickjs/quickjs-opcode.h | 371 + .../vendor/rquickjs-sys/quickjs/quickjs.c | 58389 ++++++++++++++++ .../vendor/rquickjs-sys/quickjs/quickjs.h | 1302 + .../vendor/rquickjs-sys/quickjs/repl.js | 1927 + .../vendor/rquickjs-sys/quickjs/run-test262.c | 2375 + .../vendor/rquickjs-sys/quickjs/standalone.js | 129 + .../rquickjs-sys/quickjs/test262-fast.conf | 132 + .../vendor/rquickjs-sys/quickjs/test262.conf | 399 + .../rquickjs-sys/quickjs/test262_errors.txt | 93 + .../vendor/rquickjs-sys/quickjs/tests.conf | 11 + .../rquickjs-sys/quickjs/tests/assert.js | 49 + .../rquickjs-sys/quickjs/tests/bug1221.js | 16 + .../rquickjs-sys/quickjs/tests/bug39/1.js | 6 + .../rquickjs-sys/quickjs/tests/bug39/2.js | 6 + .../rquickjs-sys/quickjs/tests/bug39/3.js | 7 + .../rquickjs-sys/quickjs/tests/bug633/0.js | 7 + .../rquickjs-sys/quickjs/tests/bug633/1.js | 4 + .../rquickjs-sys/quickjs/tests/bug633/2.js | 4 + .../rquickjs-sys/quickjs/tests/bug633/3.js | 4 + .../rquickjs-sys/quickjs/tests/bug645/0.js | 4 + .../rquickjs-sys/quickjs/tests/bug645/1.js | 9 + .../rquickjs-sys/quickjs/tests/bug645/2.js | 7 + .../rquickjs-sys/quickjs/tests/bug648.js | 13 + .../rquickjs-sys/quickjs/tests/bug652.js | 4 + .../rquickjs-sys/quickjs/tests/bug741.js | 19 + .../rquickjs-sys/quickjs/tests/bug775.js | 7 + .../rquickjs-sys/quickjs/tests/bug776.js | 7 + .../rquickjs-sys/quickjs/tests/bug832.js | 2 + .../rquickjs-sys/quickjs/tests/bug858.js | 26 + .../rquickjs-sys/quickjs/tests/bug904.js | 6 + .../rquickjs-sys/quickjs/tests/bug988.js | 7 + .../rquickjs-sys/quickjs/tests/bug999.js | 3 + .../quickjs/tests/destructured-export.js | 8 + .../quickjs/tests/detect_module/0.js | 1 + .../quickjs/tests/detect_module/1.js | 2 + .../quickjs/tests/detect_module/2.js | 1 + .../quickjs/tests/detect_module/3.js | 8 + .../quickjs/tests/detect_module/4.js | 3 + .../rquickjs-sys/quickjs/tests/empty.js | 0 .../quickjs/tests/fixture_cyclic_import.js | 2 + .../quickjs/tests/fixture_string_exports.js | 12 + .../quickjs/tests/function_source.js | 14 + .../rquickjs-sys/quickjs/tests/microbench.js | 1232 + .../quickjs/tests/null_or_undefined.js | 38 + .../quickjs/tests/str-pad-leak.js | 5 + .../rquickjs-sys/quickjs/tests/test_bigint.js | 107 + .../rquickjs-sys/quickjs/tests/test_bjson.js | 341 + .../quickjs/tests/test_builtin.js | 1232 + .../quickjs/tests/test_closure.js | 220 + .../quickjs/tests/test_cyclic_import.js | 12 + .../quickjs/tests/test_domexception.js | 35 + .../quickjs/tests/test_language.js | 748 + .../rquickjs-sys/quickjs/tests/test_loop.js | 367 + .../quickjs/tests/test_queue_microtask.js | 39 + .../rquickjs-sys/quickjs/tests/test_std.js | 314 + .../quickjs/tests/test_string_exports.js | 25 + .../rquickjs-sys/quickjs/tests/test_worker.js | 43 + .../quickjs/tests/test_worker_module.js | 30 + .../rquickjs-sys/quickjs/unicode_download.sh | 19 + .../vendor/rquickjs-sys/quickjs/unicode_gen.c | 3108 + .../rquickjs-sys/quickjs/unicode_gen_def.h | 310 + .../src/bindings/aarch64-apple-darwin.rs | 2234 + .../src/bindings/aarch64-pc-windows-msvc.rs | 2233 + .../src/bindings/aarch64-unknown-linux-gnu.rs | 2233 + .../bindings/aarch64-unknown-linux-musl.rs | 2233 + .../src/bindings/i686-unknown-linux-gnu.rs | 2202 + .../bindings/loongarch64-unknown-linux-gnu.rs | 2233 + .../loongarch64-unknown-linux-musl.rs | 2233 + .../src/bindings/wasm32-wasip1.rs | 2202 + .../src/bindings/wasm32-wasip2.rs | 2202 + .../src/bindings/x86_64-apple-darwin.rs | 2234 + .../src/bindings/x86_64-pc-windows-gnu.rs | 2233 + .../src/bindings/x86_64-pc-windows-msvc.rs | 2233 + .../src/bindings/x86_64-unknown-linux-gnu.rs | 2233 + .../src/bindings/x86_64-unknown-linux-musl.rs | 2233 + .../vendor/rquickjs-sys/src/inlines/common.rs | 117 + .../src/inlines/ptr_32_nan_boxing.rs | 98 + .../vendor/rquickjs-sys/src/inlines/ptr_64.rs | 76 + .../vendor/rquickjs-sys/src/lib.rs | 27 + host/src/cred/keys.rs | 160 +- host/src/cred/mod.rs | 2 +- host/src/cred/oauth2.rs | 7 +- host/src/cred/quickjs.rs | 275 + host/src/cred/v8.rs | 212 - host/tests/{cred_v8.rs => cred_quickjs.rs} | 91 +- host/tests/cred_quickjs_security.rs | 89 + host/tests/cred_sign.rs | 2 +- host/tests/cred_v8_security.rs | 56 - 217 files changed, 155392 insertions(+), 391 deletions(-) create mode 100644 host/cred-script/Cargo.lock create mode 100644 host/cred-script/Cargo.toml create mode 100644 host/cred-script/README.md create mode 100644 host/cred-script/build.nu create mode 100644 host/cred-script/script.wasm create mode 100644 host/cred-script/src/lib.rs create mode 100644 host/cred-script/src/main.rs create mode 100644 host/cred-script/src/tests.rs create mode 100644 host/cred-script/vendor/PATCHES.md create mode 100644 host/cred-script/vendor/llrt_utils_watts/.cargo_vcs_info.json create mode 100644 host/cred-script/vendor/llrt_utils_watts/Cargo.lock create mode 100644 host/cred-script/vendor/llrt_utils_watts/Cargo.toml create mode 100644 host/cred-script/vendor/llrt_utils_watts/Cargo.toml.orig create mode 100644 host/cred-script/vendor/llrt_utils_watts/LICENSE create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/any_of.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/bytearray_buffer.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/bytes.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/class.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/clone.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/ctx.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/error.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/error_messages.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/fs.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/hash.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/io.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/latch.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/lib.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/macros.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/mc_oneshot.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/module.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/object.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/option.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/primordials.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/provider.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/result.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/reuse_list.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/signals.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/string.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/sysinfo.rs create mode 100644 host/cred-script/vendor/llrt_utils_watts/src/time.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/.cargo_vcs_info.json create mode 100644 host/cred-script/vendor/rquickjs-sys/.gitignore create mode 100644 host/cred-script/vendor/rquickjs-sys/Cargo.lock create mode 100644 host/cred-script/vendor/rquickjs-sys/Cargo.toml create mode 100644 host/cred-script/vendor/rquickjs-sys/Cargo.toml.orig create mode 100644 host/cred-script/vendor/rquickjs-sys/Makefile create mode 100644 host/cred-script/vendor/rquickjs-sys/README.md create mode 100644 host/cred-script/vendor/rquickjs-sys/build.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs.bind.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.gitattributes create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.github/dependabot.yml create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/ci.yml create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/docs.yml create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/release.yml create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/test-docs.yml create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/tsan.yml create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/valgrind.yml create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.gitignore create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/.gitmodules create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/CMakeLists.txt create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/LICENSE create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/Makefile create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/README.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/amalgam.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/api-test.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/builtin-array-fromasync.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/builtin-array-fromasync.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/ctest.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/cutils.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/cutils.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/cxxtest.cc create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/.gitignore create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/.nvmrc create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/babel.config.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/building.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/cli.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/_category_.json create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/api.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/internals.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/intro.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/diff.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/es_features.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/installation.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/intro.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/projects.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/stdlib.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/supported_platforms.md create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/docusaurus.config.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/package-lock.json create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/package.json create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/sidebars.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/src/css/custom.css create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/static/.nojekyll create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/docs/static/img/favicon.ico create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/dtoa.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/dtoa.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/examples/fib.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/examples/fib_module.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/examples/hello.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/examples/hello_module.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/examples/meson.build create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/examples/pi_bigint.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/examples/point.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/examples/test_fib.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/examples/test_point.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/fuzz.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/gen/function_source.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/gen/hello.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/gen/hello_module.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/gen/repl.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/gen/standalone.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/gen/test_fib.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/libregexp-opcode.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/libregexp.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/libregexp.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/libunicode-table.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/libunicode.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/libunicode.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/list.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/meson.build create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/meson_options.txt create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/qjs.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/qjsc.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-atom.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-c-atomics.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-libc.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-libc.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-opcode.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/quickjs.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/quickjs.h create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/repl.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/run-test262.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/standalone.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/test262-fast.conf create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/test262.conf create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/test262_errors.txt create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests.conf create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/assert.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug1221.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug39/1.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug39/2.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug39/3.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug633/0.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug633/1.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug633/2.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug633/3.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug645/0.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug645/1.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug645/2.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug648.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug652.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug741.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug775.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug776.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug832.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug858.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug904.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug988.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/bug999.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/destructured-export.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/detect_module/0.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/detect_module/1.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/detect_module/2.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/detect_module/3.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/detect_module/4.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/empty.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/fixture_cyclic_import.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/fixture_string_exports.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/function_source.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/microbench.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/null_or_undefined.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/str-pad-leak.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_bigint.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_bjson.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_builtin.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_closure.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_cyclic_import.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_domexception.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_language.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_loop.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_queue_microtask.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_std.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_string_exports.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_worker.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/tests/test_worker_module.js create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/unicode_download.sh create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/unicode_gen.c create mode 100644 host/cred-script/vendor/rquickjs-sys/quickjs/unicode_gen_def.h create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/aarch64-apple-darwin.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/aarch64-pc-windows-msvc.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/aarch64-unknown-linux-gnu.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/aarch64-unknown-linux-musl.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/i686-unknown-linux-gnu.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/loongarch64-unknown-linux-gnu.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/loongarch64-unknown-linux-musl.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/wasm32-wasip1.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/wasm32-wasip2.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/x86_64-apple-darwin.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/x86_64-pc-windows-gnu.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/x86_64-pc-windows-msvc.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/x86_64-unknown-linux-gnu.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/bindings/x86_64-unknown-linux-musl.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/inlines/common.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/inlines/ptr_32_nan_boxing.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/inlines/ptr_64.rs create mode 100644 host/cred-script/vendor/rquickjs-sys/src/lib.rs create mode 100644 host/src/cred/quickjs.rs delete mode 100644 host/src/cred/v8.rs rename host/tests/{cred_v8.rs => cred_quickjs.rs} (74%) create mode 100644 host/tests/cred_quickjs_security.rs delete mode 100644 host/tests/cred_v8_security.rs diff --git a/Cargo.lock b/Cargo.lock index 2b33d4f..ee24910 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4994,7 +4994,9 @@ dependencies = [ "aes-gcm", "anyhow", "async-trait", + "aws-lc-rs", "base64 0.22.1", + "bytes", "chacha20poly1305", "clap", "deno_ast", diff --git a/host/Cargo.toml b/host/Cargo.toml index 553f27c..c6824be 100644 --- a/host/Cargo.toml +++ b/host/Cargo.toml @@ -51,6 +51,8 @@ ssh-key = { version = "0.6.7", features = ["encryption", "ed25519", "ecdsa", "rs uuid = { version = "1.29.0", features = ["v4"] } webauthn-rs = "0.5" openssl = { version = "0.10.82", features = ["vendored"] } +aws-lc-rs = "1.19.0" +bytes = "1.12.1" [dev-dependencies] tempfile = "3" diff --git a/host/cred-script/Cargo.lock b/host/cred-script/Cargo.lock new file mode 100644 index 0000000..e1de670 --- /dev/null +++ b/host/cred-script/Cargo.lock @@ -0,0 +1,584 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "async-lock" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0876700b0d007ad25d5508865a4259c3af9af6d296bf663a0d586d0bc3369f6f" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "cc" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff2a8126fff0f8c839080d619675a585e61720bb12d2baceae45769fd66f155" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "equivalent" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "find-msvc-tools" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hex-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f7685beb53fc20efc2605f32f5d51e9ba18b8ef237961d1760169d2290d3bee" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.191" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" + +[[package]] +name = "llrt_buffer" +version = "0.8.1-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73954ae0a8202982b83797ba4a982cdbb6f7bd9d99aafcc0aa45e98026fd7ab8" +dependencies = [ + "itoa", + "llrt_encoding", + "llrt_utils_watts", + "rquickjs", + "ryu", +] + +[[package]] +name = "llrt_build" +version = "0.8.1-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e770e9f9d0031d5788ab2f73254cdc9c516042b55db8bddf64d2f409b7015f4a" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "llrt_encoding" +version = "0.8.1-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb7748e8a3cfe2f8091fd6428c604c9bbf636a6972e5480e35fa6c245f92ea5" +dependencies = [ + "base64-simd", + "hex-simd", + "llrt_build", + "memchr", + "phf", +] + +[[package]] +name = "llrt_utils_watts" +version = "0.8.1-beta" +dependencies = [ + "libc", + "llrt_build", + "rquickjs", + "tokio", + "tracing", + "windows-sys", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "relative-path" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38540a682c6e9bca04a8bca9e5ec5a6ba168dfbb04c9998fe517a9befb92eb68" +dependencies = [ + "serde_core", +] + +[[package]] +name = "rquickjs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50dc6d6c587c339edb4769cf705867497a2baf0eca8b4645fa6ecd22f02c77a" +dependencies = [ + "rquickjs-core", + "rquickjs-macro", +] + +[[package]] +name = "rquickjs-core" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bf7840285c321c3ab20e752a9afb95548c75cd7f4632a0627cea3507e310c1" +dependencies = [ + "async-lock", + "hashbrown 0.16.1", + "relative-path", + "rquickjs-sys", +] + +[[package]] +name = "rquickjs-macro" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7106215ff41a5677b104906a13e1a440b880f4b6362b5dc4f3978c267fad2b80" +dependencies = [ + "convert_case", + "fnv", + "ident_case", + "indexmap", + "proc-macro-crate", + "proc-macro2", + "quote", + "rquickjs-core", + "syn 2.0.119", +] + +[[package]] +name = "rquickjs-sys" +version = "0.11.0" +dependencies = [ + "cc", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "sausage-cred-script" +version = "0.1.0" +dependencies = [ + "llrt_buffer", + "rquickjs", + "serde", + "serde_json", + "thiserror", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "siphasher" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "tokio" +version = "1.54.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3" +dependencies = [ + "pin-project-lite", +] + +[[package]] +name = "toml_datetime" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173f25c883cd2176a2d8212155638c0a60d484a9d84546d270866f40f56b6e49" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.19+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd43688c4858d7264ae1cf9a9f874a67c3feb74a883b1cd7bebd6a4ea8307218" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" +dependencies = [ + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" + +[[package]] +name = "unicode-ident" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3b93199df0ab874cdf0c6a94f0a0dc3423fe41f1cafb62b8bd7b1deb277aef" +dependencies = [ + "memchr", +] + +[[package]] +name = "zeroize" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" +dependencies = [ + "serde", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/host/cred-script/Cargo.toml b/host/cred-script/Cargo.toml new file mode 100644 index 0000000..377527d --- /dev/null +++ b/host/cred-script/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "sausage-cred-script" +version = "0.1.0" +edition = "2024" +publish = false + +[workspace] + +[dependencies] +rquickjs = { version = "=0.11.0", default-features = false, features = ["std"] } +llrt_buffer = "=0.8.1-beta" +thiserror = "2" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +zeroize = { version = "1", features = ["serde"] } + +[patch.crates-io] +rquickjs-sys = { path = "vendor/rquickjs-sys" } +llrt_utils_watts = { path = "vendor/llrt_utils_watts" } diff --git a/host/cred-script/README.md b/host/cred-script/README.md new file mode 100644 index 0000000..77e7f93 --- /dev/null +++ b/host/cred-script/README.md @@ -0,0 +1,46 @@ +# Credential script guest (D58) + +This host-internal WASI component runs credential validators and transforms in QuickJS. +The host embeds `script.wasm`. It never exposes this component as a world program. + +`src/lib.rs` ports v2's bounded `jsrun` evaluator. +`src/tests.rs` preserves its tests unchanged. +The vendored compatibility patches and licenses remain in `vendor/`. +`vendor/PATCHES.md` explains the compatibility fixes and memory-error classification. + +Rebuild the checked-in component from the repository root: + +```sh +CARGO_TARGET_DIR="$PWD/target/cred-guest" nix develop -c nu host/cred-script/build.nu +``` + +The script sets `CARGO_BUILD_JOBS=2` and uses the locked, separate guest workspace. +The development shell supplies the WASI C compiler and Rust target. + +Run the unchanged evaluator tests natively: + +```sh +CARGO_BUILD_JOBS=2 CARGO_TARGET_DIR="$PWD/target/cred-guest" nix develop -c cargo test --manifest-path host/cred-script/Cargo.toml --release --all-targets --locked +``` + +These tests use optimized C and Rust code, like the shipped guest. +Native debug builds exceed the 16 KiB interpreter stack. + +The JSON protocol accepts one source module, input, export name, and two limits. +The reply contains a JSON result or a static error category. +Script exception text never leaves the guest. +The guest owns its input in zeroizing buffers before the QuickJS boundary. + +The host compiles the component once and caches its compiled code. +Construct `cred::quickjs::QuickJs::default()` at startup and reuse it through `cred::script::Script`. +The injection API does not change. +Each call uses a fresh Store with linear memory limited to the clamped heap plus 8 MiB. +The margin covers the Rust stack, WASI adapter, and protocol buffers. +Only two evaluations run concurrently. Queue time counts against the deadline. +Epoch callbacks check each call's deadline independently. + +The guest receives no directories, environment variables, or network access. +Its wall clock returns zero. Its random sources use a fixed seed. +Its monotonic clock serves the evaluator's internal budget only. +JavaScript receives no clocks, random function, module loader, or host interfaces. +`Error.prepareStackTrace` is disabled and immutable. Errors retain plain stack strings. diff --git a/host/cred-script/build.nu b/host/cred-script/build.nu new file mode 100644 index 0000000..15cd10f --- /dev/null +++ b/host/cred-script/build.nu @@ -0,0 +1,9 @@ +#!/usr/bin/env nu +# Rebuild the checked-in credential script component with the pinned guest workspace. +let root = ($env.FILE_PWD | path join ../.. | path expand) +let target = ($env.CARGO_TARGET_DIR? | default ($root | path join target cred-script) | path expand) +with-env {CARGO_BUILD_JOBS: '2', CARGO_TARGET_DIR: $target} { + ^cargo build --manifest-path ($env.FILE_PWD | path join Cargo.toml) --target wasm32-wasip2 --release --locked + if $env.LAST_EXIT_CODE != 0 { error make {msg: 'The credential script guest build failed.'} } +} +cp ($target | path join wasm32-wasip2 release sausage-cred-script.wasm) ($env.FILE_PWD | path join script.wasm) diff --git a/host/cred-script/script.wasm b/host/cred-script/script.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a0861b9a5907de444561cdfdd6920ff9d2793e57 GIT binary patch literal 1564223 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%0AVYbGeF5VGe33f%G#dfrFoExguzK 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 z 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

N%MOk^^G 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

ALbC9p7LTRYBe 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

41nr+vg2;mwDe&?zayx#R4w`R2x*c@-;pT%( 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

7!~);Q396T~q3KYG5h4jXavzeZKxGG} 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�{3BO?pa03xi?V^jpqYk*dfD6u%IgErH# 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�c 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%0DDaK<7;SM{-MYZb3Y_hnkt(zyoSzz%&Qv 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 literal 0 HcmV?d00001 diff --git a/host/cred-script/src/lib.rs b/host/cred-script/src/lib.rs new file mode 100644 index 0000000..7cf103a --- /dev/null +++ b/host/cred-script/src/lib.rs @@ -0,0 +1,243 @@ +//! Bounded, stateless ES modules with JSON text boundaries. No host capabilities. +use rquickjs::{Context, Ctx, Function, Module, Promise, Runtime, Value, context::intrinsic}; +use std::{ + cell::Cell, + rc::Rc, + time::{Duration, Instant}, +}; + +/// Requested limits. Values are clamped by the evaluator, including zero. +#[derive(Clone, Copy, Debug, Default)] +pub struct Limits { + pub max_time_ms: Option, + pub max_memory_bytes: Option, + pub max_stack_bytes: Option, +} +impl Limits { + /// Effective time (1..1000ms), heap (256KiB..32MiB), stack (4..16KiB). + pub fn clamped(self) -> Self { + Self { + max_time_ms: Some(self.max_time_ms.unwrap_or(100).clamp(1, 1000)), + max_memory_bytes: Some( + self.max_memory_bytes + .unwrap_or(8 * 1024 * 1024) + .clamp(256 * 1024, 32 * 1024 * 1024), + ), + max_stack_bytes: Some( + self.max_stack_bytes + .unwrap_or(16 * 1024) + .clamp(4 * 1024, 16 * 1024), + ), + } + } +} +/// Stable error categories, independent of QuickJS's exception wording. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ErrorKind { + Limit, + Syntax, + Throw, + NonJson, + Engine, +} +/// An evaluation failure. Error text can include script-provided messages. +#[derive(Debug, thiserror::Error)] +#[error("{message}")] +pub struct Error { + pub kind: ErrorKind, + pub message: String, +} +fn failure(kind: ErrorKind, message: impl Into) -> Error { + Error { + kind, + message: message.into(), + } +} + +struct Budget { + start: Instant, + time: Duration, + ticks: Cell, + limited: Cell, +} +impl Budget { + // A finite job/callback allowance is also needed for a stream of tiny jobs + // and for hosts with a stalled monotonic clock. Not an instruction count. + fn step(&self) -> bool { + self.ticks.set(self.ticks.get().saturating_add(1)); + let stop = self.ticks.get() >= 100_000 || self.start.elapsed() >= self.time; + self.limited.set(self.limited.get() || stop); + self.limited.get() + } + fn check(&self) -> Result<(), Error> { + if self.step() { + Err(failure( + ErrorKind::Limit, + "JavaScript execution limit exceeded", + )) + } else { + Ok(()) + } + } +} +unsafe extern "C" { + fn sausage_js_had_oom(ctx: *mut std::ffi::c_void) -> std::ffi::c_int; +} +fn memory_limited(ctx: &Ctx<'_>) -> bool { + // The live Ctx owns this context and holds the runtime lock. + unsafe { sausage_js_had_oom(ctx.as_raw().as_ptr().cast()) != 0 } +} +fn js_error(ctx: &Ctx<'_>, err: rquickjs::Error, phase: ErrorKind, budget: &Budget) -> Error { + if memory_limited(ctx) { + return failure(ErrorKind::Limit, "JavaScript memory limit exceeded"); + } + if budget.limited.get() { + return failure(ErrorKind::Limit, "JavaScript execution limit exceeded"); + } + let mut kind = phase; + let mut message = err.to_string(); + if matches!(err, rquickjs::Error::Exception) { + let thrown = ctx.catch(); + if let Some(object) = thrown.as_object() { + if let Ok(text) = object.get::<_, String>("message") { + message = text; + } + // Only genuine engine Error instances determine resource/syntax kinds; + // plain thrown objects remain throws even if they mimic the message. + if thrown.is_error() { + if message.contains("out of memory") || message.contains("stack size exceeded") { + kind = ErrorKind::Limit; + } else if object + .get::<_, String>("name") + .is_ok_and(|n| n == "SyntaxError") + { + kind = ErrorKind::Syntax; + } + } + } else if let Some(text) = thrown.as_string() + && let Ok(text) = text.to_string() + { + message = text; + } + } else if matches!(err, rquickjs::Error::Allocation) { + kind = ErrorKind::Limit; + } + if memory_limited(ctx) { + return failure( + ErrorKind::Limit, + "JavaScript memory limit exceeded while reading error", + ); + } + if budget.check().is_err() { + return failure( + ErrorKind::Limit, + "JavaScript execution limit exceeded while reading error", + ); + } + failure(kind, message) +} +fn settle<'js>( + ctx: &Ctx<'js>, + promise: Promise<'js>, + budget: &Budget, +) -> Result, Error> { + loop { + budget.check()?; + if let Some(result) = promise.result::() { + return result.map_err(|e| js_error(ctx, e, ErrorKind::Throw, budget)); + } + // This is synchronous queue draining, not polling an external resource. + if !ctx.execute_pending_job() { + return Err(failure( + ErrorKind::Engine, + "Promise is pending with no runnable jobs (no ambient async capabilities)", + )); + } + } +} + +/// Compile an ES module, call its selected export (default `default`) with parsed +/// JSON, settle its returned Promise, and JSON.stringify the result. Fresh runtime +/// each call. Only LLRT's atob/btoa globals are retained, with no module loader +/// or ambient host capabilities. JSON.stringify +/// semantics apply (unsupported object properties omitted, nonfinite => null). +/// Limits cover compilation, execution, job draining and serialization; QuickJS +/// interrupts are cooperative, not preemptive deadlines for every C builtin. +pub fn evaluate( + script: &str, + input: &str, + export: Option<&str>, + limits: Limits, +) -> Result { + let limits = limits.clamped(); + let budget = Rc::new(Budget { + start: Instant::now(), + time: Duration::from_millis(limits.max_time_ms.unwrap_or(100)), + ticks: Cell::new(0), + limited: Cell::new(false), + }); + let rt = Runtime::new().map_err(|e| failure(ErrorKind::Engine, e.to_string()))?; + rt.set_memory_limit(limits.max_memory_bytes.unwrap_or(8 * 1024 * 1024)); + rt.set_max_stack_size(limits.max_stack_bytes.unwrap_or(16 * 1024)); + let cb = budget.clone(); + rt.set_interrupt_handler(Some(Box::new(move || cb.step()))); + // LLRT's BasePrimordials needs Date during initialization, as well as the + // pure collection/regexp/typed-array intrinsics. Date is removed before + // user code runs; no network, filesystem, process or timer modules load. + let context = Context::custom::<( + intrinsic::Eval, + intrinsic::Json, + intrinsic::Promise, + intrinsic::Date, + intrinsic::MapSet, + intrinsic::RegExp, + intrinsic::Proxy, + intrinsic::TypedArrays, + )>(&rt) + .map_err(|e| failure(ErrorKind::Limit, format!("context creation failed: {e}")))?; + context.with(|ctx| { + llrt_buffer::init(&ctx) + .map_err(|e| js_error(&ctx, e, ErrorKind::Engine, &budget))?; + // Retain only atob/btoa from the published buffer initializer. Buffer's + // external allocations bypass the heap limit; Blob/File are unnecessary + // and File exposes the clock. Buffer has both a global lexical class + // binding and a globalThis property: clear both. Date is init-only. + // Disable QuickJS's structured stack hook before it can expose call sites. + ctx.eval::<(), _>("Object.defineProperty(Error, 'prepareStackTrace', { value: undefined, writable: false, configurable: false }); Buffer = undefined; delete globalThis.Buffer; delete Math.random; delete globalThis.Date; delete globalThis.Blob; delete globalThis.File; for (const name of ['WebAssembly', 'SharedArrayBuffer', 'Atomics', 'Intl', '__infra', '__bootstrap', 'queueMicrotask']) delete globalThis[name];") + .map_err(|e| js_error(&ctx, e, ErrorKind::Engine, &budget))?; + let input = ctx + .json_parse(input) + .map_err(|e| js_error(&ctx, e, ErrorKind::Syntax, &budget))?; + let module = Module::declare(ctx.clone(), "jsrun:entry", script) + .map_err(|e| js_error(&ctx, e, ErrorKind::Syntax, &budget))?; + let (module, ready) = module + .eval() + .map_err(|e| js_error(&ctx, e, ErrorKind::Throw, &budget))?; + settle(&ctx, ready, &budget)?; + let function: Function = module + .get(export.unwrap_or("default")) + .map_err(|e| js_error(&ctx, e, ErrorKind::Engine, &budget))?; + let mut value: Value = function + .call((input,)) + .map_err(|e| js_error(&ctx, e, ErrorKind::Throw, &budget))?; + if let Some(promise) = value.as_promise() { + value = settle(&ctx, promise.clone(), &budget)?; + } + let text = ctx + .json_stringify(value) + .map_err(|e| js_error(&ctx, e, ErrorKind::NonJson, &budget))? + .ok_or_else(|| { + failure( + ErrorKind::NonJson, + "result is undefined, a function, or otherwise not JSON serializable", + ) + })? + .to_string() + .map_err(|e| js_error(&ctx, e, ErrorKind::NonJson, &budget))?; + budget.check()?; + Ok(text) + }) +} + +#[cfg(test)] +mod tests; diff --git a/host/cred-script/src/main.rs b/host/cred-script/src/main.rs new file mode 100644 index 0000000..8408269 --- /dev/null +++ b/host/cred-script/src/main.rs @@ -0,0 +1,58 @@ +//! One JSON call over stdin/stdout. Script exception text never leaves this guest. +use sausage_cred_script::{ErrorKind, Limits, evaluate}; +use std::io::{Read, Write}; +use zeroize::Zeroizing; + +#[derive(serde::Deserialize)] +struct Request { + source: String, + input: Zeroizing, + export: Option, + max_time_ms: u64, + max_memory_bytes: usize, +} + +fn run() -> Result<(), Box> { + let mut wire = Zeroizing::new(String::new()); + std::io::stdin().read_to_string(&mut wire)?; + let request: Request = serde_json::from_str(&wire)?; + let result = evaluate( + &request.source, + &request.input, + request.export.as_deref(), + Limits { + max_time_ms: Some(request.max_time_ms), + max_memory_bytes: Some(request.max_memory_bytes), + ..Limits::default() + }, + ); + let response = match result { + Ok(result) => serde_json::json!({"result": result}), + Err(error) => serde_json::json!({"kind": match error.kind { + ErrorKind::Limit => "Limit", + ErrorKind::Syntax => "Syntax", + ErrorKind::Throw => "Throw", + ErrorKind::NonJson => "NonJson", + ErrorKind::Engine => "Engine", + }}), + }; + serde_json::to_writer(std::io::stdout().lock(), &response)?; + std::io::stdout().flush()?; + Ok(()) +} +fn main() { + if run().is_err() { + std::process::exit(1); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn request_input_has_zeroizing_ownership() { + let request: Request = serde_json::from_str(r#"{"source":"export default x=>x","input":"null","export":null,"max_time_ms":100,"max_memory_bytes":8388608}"#).unwrap(); + let _: &Zeroizing = &request.input; + } +} diff --git a/host/cred-script/src/tests.rs b/host/cred-script/src/tests.rs new file mode 100644 index 0000000..ddcde7b --- /dev/null +++ b/host/cred-script/src/tests.rs @@ -0,0 +1,196 @@ +use super::*; +fn run(s: &str) -> Result { + evaluate(s, "null", None, Limits::default()) +} +#[test] +fn module_default_and_named() { + assert_eq!( + evaluate( + "export default x => ({value:x}); export const other=x=>x+1", + "42", + None, + Limits::default() + ) + .unwrap(), + "{\"value\":42}" + ); + assert_eq!( + evaluate( + "export const other=x=>x+1", + "42", + Some("other"), + Limits::default() + ) + .unwrap(), + "43" + ); + assert_eq!(run("export default x=>null").unwrap(), "null"); +} +#[test] +fn promise_settlement() { + assert_eq!( + run("export default async x => { await Promise.resolve(); return 42; }").unwrap(), + "42" + ); + assert_eq!( + run("await Promise.resolve(); export default x=>true").unwrap(), + "true" + ); + for s in [ + "export default x=>Promise.reject(new Error('rejected'))", + "export default async x=>{ throw 'rejected'; }", + "await Promise.reject('rejected'); export default x=>true", + ] { + let e = run(s).unwrap_err(); + assert_eq!(e.kind, ErrorKind::Throw); + assert_eq!(e.message, "rejected"); + } + assert_eq!( + run("export default x=>new Promise(()=>{})") + .unwrap_err() + .kind, + ErrorKind::Engine + ); +} +#[test] +fn typed_errors() { + assert_eq!(run("export default (").unwrap_err().kind, ErrorKind::Syntax); + assert_eq!( + run("export default x=>{throw new Error('oops')}") + .unwrap_err() + .kind, + ErrorKind::Throw + ); + for s in [ + "export default x=>undefined", + "export default x=>(()=>1)", + "export default x=>{let a={};a.a=a;return a}", + "export default x=>Symbol()", + ] { + assert_eq!(run(s).unwrap_err().kind, ErrorKind::NonJson); + } + assert_eq!( + evaluate("export default x=>x", "not json", None, Limits::default()) + .unwrap_err() + .kind, + ErrorKind::Syntax + ); + assert_eq!(run("export const x=1").unwrap_err().kind, ErrorKind::Engine); + assert_eq!(run("export default 1").unwrap_err().kind, ErrorKind::Engine); +} +#[test] +fn recursion_is_bounded() { + for stack in [4096, 16384, usize::MAX] { + let e = evaluate( + "export default x=>{function f(){return f()+1}return f()}", + "null", + None, + Limits { + max_stack_bytes: Some(stack), + ..Limits::default() + }, + ) + .unwrap_err(); + eprintln!("STACK {stack}: {e:?}"); + assert_eq!(e.kind, ErrorKind::Limit); + assert!(e.message.contains("stack")); + } +} +#[test] +fn runaway_loop_and_jobs() { + for s in [ + "export default x=>{while(true){}}", + "while(true){};export default x=>x", + "export default x=>({toJSON(){while(true){}}})", + "export default x=>{throw {get message(){while(true){}}}}", + "export default x=>new Promise(()=>{function f(){Promise.resolve().then(f)};f()})", + ] { + let start = Instant::now(); + assert_eq!(run(s).unwrap_err().kind, ErrorKind::Limit); + assert!(start.elapsed() < Duration::from_secs(2)); + } +} +#[test] +fn runaway_allocation() { + let e = evaluate( + "export default x=>{let a=[];while(1)a.push('abcdefghijklmnopqrstuvwxyz'+a.length)}", + "null", + None, + Limits { + max_time_ms: Some(1000), + max_memory_bytes: Some(1024 * 1024), + ..Limits::default() + }, + ) + .unwrap_err(); + eprintln!("HEAP {e:?}"); + assert_eq!(e.kind, ErrorKind::Limit); + assert!(e.message.contains("memory")); +} +#[test] +fn forbidden_globals_and_imports() { + for name in [ + "Date", + "performance", + "Math.random", + "fetch", + "XMLHttpRequest", + "require", + "process", + "std", + "os", + "fs", + "crypto", + "console", + "setTimeout", + ] { + assert_eq!( + run(&format!("export default x=>typeof {name}")).unwrap(), + "\"undefined\"", + "{name}" + ); + } + assert!(run("import x from 'fs';export default x=>x").is_err()); + assert_eq!( + run("export default x=>import('fs')").unwrap_err().kind, + ErrorKind::Throw + ); +} +#[test] +fn isolation_and_limits() { + run("export default x=>{globalThis.leak=42;return true}").unwrap(); + assert_eq!( + run("export default x=>typeof leak").unwrap(), + "\"undefined\"" + ); + assert_eq!( + Limits { + max_time_ms: Some(u64::MAX), + max_memory_bytes: Some(usize::MAX), + max_stack_bytes: Some(usize::MAX) + } + .clamped() + .max_time_ms, + Some(1000) + ); + assert_eq!( + Limits { + max_time_ms: Some(0), + ..Limits::default() + } + .clamped() + .max_time_ms, + Some(1) + ); +} +#[test] +fn timings() { + let start = Instant::now(); + assert_eq!(run("export default x=>true").unwrap(), "true"); + eprintln!("TIMING first eval {}us", start.elapsed().as_micros()); + let start = Instant::now(); + for _ in 0..100 { + assert_eq!(run("export default x=>true").unwrap(), "true"); + } + eprintln!("TIMING 100 evals {}us", start.elapsed().as_micros()); +} diff --git a/host/cred-script/vendor/PATCHES.md b/host/cred-script/vendor/PATCHES.md new file mode 100644 index 0000000..b94e45c --- /dev/null +++ b/host/cred-script/vendor/PATCHES.md @@ -0,0 +1,50 @@ +# Local compatibility patches + +## LLRT utilities (SAU-330) + +`llrt_buffer = 0.8.1-beta` and `llrt_encoding` remain published crate dependencies, +matching rquickjs 0.11 without changing the engine/vendor patches below. +The published `llrt_utils_watts = 0.8.1-beta` does not compile for wasm32-wasip2: +`signals::kill` unconditionally references `kill_process_raw` and `is_not_found`, +but those are only defined on Unix/Windows. The failed unpatched build is archived +at `/logs/cargo/2026-10-28/01a184d5-151b-7454-8333-b5d1d468b6d6.stderr.log`. + +Fallback: `llrt_utils_watts/` is the unchanged published crate archive from +https://static.crates.io/crates/llrt_utils_watts/llrt_utils_watts-0.8.1-beta.crate +(SHA256 `5ace6f63a6b60a3bf738bf19f393c834c83a06d9e52c31d1c30a526584519569`), +except `src/lib.rs` adds `#[cfg(any(unix, windows))]` to `pub mod signals`. +The root Cargo patch points here. No utility module is registered as a JS module. +The upstream Apache-2.0 license is included (absent in the published archive). + +This build-only patch does not alter Buffer. Before user module initialization, +the evaluator clears Buffer's global lexical binding and deletes its global-object +property, and removes Blob, File and Date, retaining only atob/btoa from the module. +SAU-330's mediator decision excludes the Node Buffer API rather than patching +its external-allocation heap bypass or empty-fill panic. Tests cover absent +identifiers, globalThis properties and global own-property names, plus base64 +errors and clean near-heap-limit failure. See +`/docs/symphony/artifacts/SAU-330/implementation.md` for evidence. + +## QuickJS (SAU-103) + +`rquickjs-sys` was downloaded unchanged from https://crates.io/api/v1/crates/rquickjs-sys/0.11.0/download, then changed in exactly two files: + +- `quickjs/quickjs.c`, `update_stack_limit`: remove the `__wasi__` special case that sets `stack_limit = 0` regardless of `JS_SetMaxStackSize`. Use the normal stack-top-minus-size implementation on WASI too. Without this patch the recursion test traps the WASM instance even with 16KiB / 256KiB limits. With the patch it returns `Maximum call stack size exceeded`. +- `build.rs`: skip upstream WASI SDK download/CC override when `CC_wasm32_wasip2` is supplied, letting `cc` honor cargo.build's target-specific CC/AR. Also emit the selected compiler/args as a diagnostic. + +No engine features or host APIs were added. Keep this patch when reusing the evaluator; setting the Rust stack-limit API alone is **not sufficient** with unmodified rquickjs-sys 0.11.0. Upstream 0.14.0's source was inspected (not compiled) and still contains the WASI stack-limit bypass. + +The bundled sources retain their upstream notices/licenses. This is a spike-local vendoring choice, not an SDK or live toolchain change. + +## Sausage memory-error classification (D58) + +`quickjs.c` records a sticky flag when `JS_ThrowOutOfMemory` runs. +`sausage_js_had_oom` exposes that flag to the guest's Rust evaluator. +`quickjs.h` declares this guest-internal function. +`build.rs` watches the QuickJS source directory, so Cargo rebuilds the library after a patch. +It adds no JavaScript API or host import. + +A full heap can prevent QuickJS from creating its error object. +The unchanged `runaway_allocation` test reproduced that case and received `Throw` instead of `Limit`. +The flag preserves the memory-error category without another allocation. +Each evaluation creates a fresh runtime, so it also resets the flag. diff --git a/host/cred-script/vendor/llrt_utils_watts/.cargo_vcs_info.json b/host/cred-script/vendor/llrt_utils_watts/.cargo_vcs_info.json new file mode 100644 index 0000000..a9d915f --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/.cargo_vcs_info.json @@ -0,0 +1,7 @@ +{ + "git": { + "sha1": "2946a77260e8cdd314f92a9789635cd4f7b825bf", + "dirty": true + }, + "path_in_vcs": "libs/llrt_utils" +} \ No newline at end of file diff --git a/host/cred-script/vendor/llrt_utils_watts/Cargo.lock b/host/cred-script/vendor/llrt_utils_watts/Cargo.lock new file mode 100644 index 0000000..47ba0b3 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/Cargo.lock @@ -0,0 +1,879 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "llrt_build" +version = "0.8.1-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e770e9f9d0031d5788ab2f73254cdc9c516042b55db8bddf64d2f409b7015f4a" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "llrt_test" +version = "0.8.1-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44ff8cf3b62144ca17b132f7fedf983d935573684a140f5e7a5f81a06b215665" +dependencies = [ + "rquickjs", + "tokio", + "uuid", +] + +[[package]] +name = "llrt_utils_watts" +version = "0.8.1-beta" +dependencies = [ + "libc", + "llrt_build", + "llrt_test", + "rquickjs", + "tokio", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "relative-path" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0" +dependencies = [ + "serde", +] + +[[package]] +name = "rquickjs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50dc6d6c587c339edb4769cf705867497a2baf0eca8b4645fa6ecd22f02c77a" +dependencies = [ + "rquickjs-core", + "rquickjs-macro", +] + +[[package]] +name = "rquickjs-core" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bf7840285c321c3ab20e752a9afb95548c75cd7f4632a0627cea3507e310c1" +dependencies = [ + "async-lock", + "hashbrown 0.16.1", + "relative-path", + "rquickjs-sys", +] + +[[package]] +name = "rquickjs-macro" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7106215ff41a5677b104906a13e1a440b880f4b6362b5dc4f3978c267fad2b80" +dependencies = [ + "convert_case", + "fnv", + "ident_case", + "indexmap", + "proc-macro-crate", + "proc-macro2", + "quote", + "rquickjs-core", + "syn", +] + +[[package]] +name = "rquickjs-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27344601ef27460e82d6a4e1ecb9e7e99f518122095f3c51296da8e9be2b9d83" +dependencies = [ + "cc", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "syn" +version = "2.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.8+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc" +dependencies = [ + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" + +[[package]] +name = "unicode-ident" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "uuid" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +dependencies = [ + "getrandom", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/host/cred-script/vendor/llrt_utils_watts/Cargo.toml b/host/cred-script/vendor/llrt_utils_watts/Cargo.toml new file mode 100644 index 0000000..26f911f --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/Cargo.toml @@ -0,0 +1,74 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "llrt_utils_watts" +version = "0.8.1-beta" +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "LLRT utilities" +readme = false +license = "Apache-2.0" +repository = "https://github.com/awslabs/llrt" + +[features] +all = [ + "fs", + "bytearray-buffer", +] +bytearray-buffer = ["tokio/sync"] +default = ["all"] +fs = ["tokio/fs"] + +[lib] +name = "llrt_utils_watts" +path = "src/lib.rs" + +[dependencies.rquickjs] +version = "0.11" +features = ["macro"] +default-features = false + +[dependencies.tokio] +version = "1" +features = ["sync"] +default-features = false + +[dependencies.tracing] +version = "0.1" +default-features = false + +[dev-dependencies.llrt_test] +version = "0.8.1-beta" + +[dev-dependencies.tokio] +version = "1" +features = ["full"] + +[build-dependencies.llrt_build] +version = "0.8.1-beta" + +[target."cfg(unix)".dependencies.libc] +version = "0.2" +default-features = false + +[target."cfg(windows)".dependencies.windows-sys] +version = "0.61" +features = [ + "Win32_Foundation", + "Win32_System_Threading", +] +default-features = false diff --git a/host/cred-script/vendor/llrt_utils_watts/Cargo.toml.orig b/host/cred-script/vendor/llrt_utils_watts/Cargo.toml.orig new file mode 100644 index 0000000..6abd709 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/Cargo.toml.orig @@ -0,0 +1,34 @@ +[package] +name = "llrt_utils_watts" +description = "LLRT utilities" +version = "0.8.1-beta" +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/awslabs/llrt" + +[features] +default = ["all"] +all = ["fs", "bytearray-buffer"] + +fs = ["tokio/fs"] +bytearray-buffer = ["tokio/sync"] + +[dependencies] +rquickjs = { version = "0.11", features = [ + "macro", +], default-features = false } +tokio = { version = "1", features = ["sync"], default-features = false } +tracing = { version = "0.1", default-features = false } + +[target.'cfg(unix)'.dependencies] +libc = { version = "0.2", default-features = false } + +[target.'cfg(windows)'.dependencies] +windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_System_Threading"], default-features = false } + +[dev-dependencies] +llrt_test = { version = "0.8.1-beta", path = "../llrt_test" } +tokio = { version = "1", features = ["full"] } + +[build-dependencies] +llrt_build = { version = "0.8.1-beta", path = "../llrt_build" } diff --git a/host/cred-script/vendor/llrt_utils_watts/LICENSE b/host/cred-script/vendor/llrt_utils_watts/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. \ No newline at end of file diff --git a/host/cred-script/vendor/llrt_utils_watts/src/any_of.rs b/host/cred-script/vendor/llrt_utils_watts/src/any_of.rs new file mode 100644 index 0000000..f76b275 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/any_of.rs @@ -0,0 +1,298 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{ + class::{Trace, Tracer}, + Ctx, FromJs, IntoJs, JsLifetime, Result, Value, +}; + +macro_rules! define_any_of { + ($name:ident, $($variant:ident),+) => { + #[derive(Debug, Clone)] + pub enum $name<$($variant),+> { + $( + $variant($variant), + )+ + } + + define_any_of_from_js!($name, $($variant),+); + + impl<'js, $($variant: IntoJs<'js>),+> IntoJs<'js> for $name<$($variant),+> { + fn into_js(self, ctx: &Ctx<'js>) -> Result> { + match self { + $( + Self::$variant(val) => val.into_js(ctx), + )+ + } + } + } + + unsafe impl<'js, $($variant: JsLifetime<'js>),+> JsLifetime<'js> for $name<$($variant),+> { + type Changed<'to> = $name<$($variant::Changed<'to>),+>; + } + + impl<'js, $($variant: Trace<'js>),+> Trace<'js> for $name<$($variant),+> { + fn trace<'a>(&self, tracer: Tracer<'a, 'js>) { + match self { + $( + Self::$variant(val) => val.trace(tracer), + )+ + } + } + } + + define_any_of_methods!($name, $($variant),+); + }; +} + +macro_rules! define_any_of_from_js { + ($name:ident, $first:ident, $($rest:ident),+) => { + impl<'js, $first: FromJs<'js>, $($rest: FromJs<'js>),+> FromJs<'js> for $name<$first, $($rest),+> { + fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + define_any_of_from_js_impl!($name, ctx, value, $first, $($rest),+) + } + } + }; +} + +macro_rules! define_any_of_from_js_impl { + ($name:ident, $ctx:ident, $value:ident, $first:ident) => { + $first::from_js($ctx, $value).map($name::$first) + }; + + ($name:ident, $ctx:ident, $value:ident, $first:ident, $($rest:ident),+) => { + $first::from_js($ctx, $value.clone()).map($name::$first).or_else(|error| { + if error.is_from_js() { + define_any_of_from_js_impl!($name, $ctx, $value, $($rest),+) + } else { + Err(error) + } + }) + }; +} + +macro_rules! define_any_of_variant_methods { + ($variant:ident, $is_fn:ident, $as_fn:ident, $as_mut_fn:ident, $into_fn:ident) => { + #[allow(dead_code)] + pub fn $is_fn(&self) -> bool { + matches!(self, Self::$variant(_)) + } + + #[allow(dead_code)] + pub fn $as_fn(&self) -> Option<&$variant> { + match self { + Self::$variant(val) => Some(val), + _ => None, + } + } + + #[allow(dead_code)] + pub fn $as_mut_fn(&mut self) -> Option<&mut $variant> { + match self { + Self::$variant(val) => Some(val), + _ => None, + } + } + + #[allow(dead_code)] + pub fn $into_fn(self) -> std::result::Result<$variant, Self> { + match self { + Self::$variant(val) => Ok(val), + other => Err(other), + } + } + }; + + (A) => { + define_any_of_variant_methods!(A, is_a, as_a, as_a_mut, into_a); + }; + (B) => { + define_any_of_variant_methods!(B, is_b, as_b, as_b_mut, into_b); + }; + (C) => { + define_any_of_variant_methods!(C, is_c, as_c, as_c_mut, into_c); + }; + (D) => { + define_any_of_variant_methods!(D, is_d, as_d, as_d_mut, into_d); + }; + (E) => { + define_any_of_variant_methods!(E, is_e, as_e, as_e_mut, into_e); + }; + (F) => { + define_any_of_variant_methods!(F, is_f, as_f, as_f_mut, into_f); + }; + (G) => { + define_any_of_variant_methods!(G, is_g, as_g, as_g_mut, into_g); + }; + (H) => { + define_any_of_variant_methods!(H, is_h, as_h, as_h_mut, into_h); + }; +} + +macro_rules! define_any_of_methods { + ($name:ident, $($variant:ident),+) => { + impl<$($variant),+> $name<$($variant),+> { + $( + define_any_of_variant_methods!($variant); + )+ + } + }; +} + +define_any_of!(AnyOf2, A, B); +define_any_of!(AnyOf3, A, B, C); +define_any_of!(AnyOf4, A, B, C, D); +define_any_of!(AnyOf5, A, B, C, D, E); +define_any_of!(AnyOf6, A, B, C, D, E, F); +define_any_of!(AnyOf7, A, B, C, D, E, F, G); +define_any_of!(AnyOf8, A, B, C, D, E, F, G, H); + +#[cfg(test)] +mod tests { + use super::*; + use rquickjs::{Context, Runtime}; + + #[test] + fn test_any_of_string_number() { + let rt = Runtime::new().unwrap(); + let ctx = Context::full(&rt).unwrap(); + + ctx.with(|ctx| { + // Test string conversion + let val: Value = ctx.eval("'hello'").unwrap(); + let any: AnyOf2 = AnyOf2::from_js(&ctx, val).unwrap(); + assert!(any.is_a()); + assert_eq!(any.as_a().unwrap(), "hello"); + assert!(!any.is_b()); + assert!(any.as_b().is_none()); + + // Test number conversion + let val: Value = ctx.eval("42").unwrap(); + let any: AnyOf2 = AnyOf2::from_js(&ctx, val).unwrap(); + assert!(!any.is_a()); + assert!(any.is_b()); + assert_eq!(*any.as_b().unwrap(), 42); + }); + } + + #[test] + fn test_any_of_fallback() { + let rt = Runtime::new().unwrap(); + let ctx = Context::full(&rt).unwrap(); + + ctx.with(|ctx| { + // Test that it tries in order + let val: Value = ctx.eval("true").unwrap(); + let any: AnyOf3 = AnyOf3::from_js(&ctx, val).unwrap(); + assert!(any.is_c()); + assert!(*any.as_c().unwrap()); + assert!(!any.is_a()); + assert!(!any.is_b()); + }); + } + + #[test] + fn test_any_of_into_js() { + let rt = Runtime::new().unwrap(); + let ctx = Context::full(&rt).unwrap(); + + ctx.with(|ctx| { + let any: AnyOf2 = AnyOf2::A("test".to_string()); + let val: Value = any.into_js(&ctx).unwrap(); + let result: String = val.get().unwrap(); + assert_eq!(result, "test"); + + let any: AnyOf2 = AnyOf2::B(99); + let val: Value = any.into_js(&ctx).unwrap(); + let result: i32 = val.get().unwrap(); + assert_eq!(result, 99); + }); + } + + #[test] + fn test_any_of_methods() { + let rt = Runtime::new().unwrap(); + let ctx = Context::full(&rt).unwrap(); + + ctx.with(|ctx| { + // Test all methods for variant A + let val: Value = ctx.eval("'test'").unwrap(); + let any: AnyOf3 = AnyOf3::from_js(&ctx, val).unwrap(); + assert!(any.is_a()); + assert_eq!(any.as_a().unwrap(), "test"); + assert_eq!(any.into_a().unwrap(), "test"); + + // Test all methods for variant B + let val: Value = ctx.eval("42").unwrap(); + let any: AnyOf3 = AnyOf3::from_js(&ctx, val).unwrap(); + assert!(any.is_b()); + assert_eq!(*any.as_b().unwrap(), 42); + assert_eq!(any.into_b().unwrap(), 42); + + // Test all methods for variant C + let val: Value = ctx.eval("true").unwrap(); + let any: AnyOf3 = AnyOf3::from_js(&ctx, val).unwrap(); + assert!(any.is_c()); + assert!(*any.as_c().unwrap()); + assert!(any.into_c().unwrap()); + }); + } + + #[test] + fn test_any_of_mutable_methods() { + let rt = Runtime::new().unwrap(); + let ctx = Context::full(&rt).unwrap(); + + ctx.with(|ctx| { + let val: Value = ctx.eval("42").unwrap(); + let mut any: AnyOf4 = AnyOf4::from_js(&ctx, val).unwrap(); + + if let Some(n) = any.as_b_mut() { + *n = 100; + } + + assert_eq!(any.into_b().unwrap(), 100); + }); + } + + #[test] + fn test_any_of_error_propagation() { + use rquickjs::{Array, Object}; + + let rt = Runtime::new().unwrap(); + let ctx = Context::full(&rt).unwrap(); + + ctx.with(|ctx| { + // Test that conversion errors cause fallback to next type + let val: Value = ctx.eval("42").unwrap(); + let any: AnyOf2 = AnyOf2::from_js(&ctx, val).unwrap(); + assert!(any.is_b()); + + // Test that all types fail results in an error + let val: Value = ctx.eval("null").unwrap(); + let result: Result> = AnyOf2::from_js(&ctx, val); + assert!(result.is_err()); + }); + } + + #[test] + fn test_any_of_conversion_order() { + let rt = Runtime::new().unwrap(); + let ctx = Context::full(&rt).unwrap(); + + ctx.with(|ctx| { + // Test that conversion happens in order A, B, C, D, E + // Since 42 can be converted to f64, i32, etc., but String comes first and fails, + // it should try the next successful conversion + let val: Value = ctx.eval("42").unwrap(); + + // String should fail, so it tries i32 which succeeds + let any: AnyOf3 = AnyOf3::from_js(&ctx, val).unwrap(); + assert!(any.is_b()); + + // If we flip the order, f64 would be tried first (but both work) + let val: Value = ctx.eval("3.14").unwrap(); + let any: AnyOf3 = AnyOf3::from_js(&ctx, val).unwrap(); + assert!(any.is_b()); // f64 should succeed first + }); + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/bytearray_buffer.rs b/host/cred-script/vendor/llrt_utils_watts/src/bytearray_buffer.rs new file mode 100644 index 0000000..410e940 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/bytearray_buffer.rs @@ -0,0 +1,226 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use std::{ + cmp::min, + collections::VecDeque, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, Mutex, + }, +}; + +use tokio::sync::{Notify, Semaphore}; + +#[derive(Clone)] +pub struct BytearrayBuffer { + inner: Arc>>, + max_capacity: Arc, + len: Arc, + notify: Arc, + closed: Arc, + write_semaphore: Arc, +} + +impl BytearrayBuffer { + pub fn new(capacity: usize) -> Self { + let queue = VecDeque::with_capacity(capacity); + let capacity = queue.capacity(); + Self { + inner: Arc::new(Mutex::new(queue)), + len: Arc::new(AtomicUsize::new(0)), + max_capacity: Arc::new(AtomicUsize::new(capacity)), + notify: Arc::new(Notify::new()), + closed: Arc::new(AtomicBool::new(false)), + write_semaphore: Arc::new(Semaphore::new(1)), + } + } + + pub fn len(&self) -> usize { + self.len.load(Ordering::Relaxed) + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[allow(dead_code)] + pub fn write_forced(&self, item: &[u8]) { + let mut inner = self.inner.lock().unwrap(); + inner.extend(item); + let capacity = inner.capacity(); + self.len.fetch_add(item.len(), Ordering::Relaxed); + self.max_capacity.store(capacity, Ordering::Relaxed); + } + + pub async fn write(&self, item: &mut [u8]) -> usize { + let _ = self.write_semaphore.acquire().await.unwrap(); + let mut slice_index = 0; + loop { + let max_capacity = self.max_capacity.load(Ordering::Relaxed); + if self.closed.load(Ordering::Relaxed) { + return max_capacity; + } + + let len = self.len.load(Ordering::Relaxed); + + let available = max_capacity - len; + + if available > 0 { + let end_index = min(item.len() - 1, slice_index + available - 1); + let sub_slice = &item[slice_index..=end_index]; + let slice_length = sub_slice.len(); + slice_index += slice_length; + + self.inner.lock().unwrap().extend(sub_slice); + self.len.fetch_add(slice_length, Ordering::Relaxed); + + if slice_index == item.len() { + return max_capacity; + } + } + self.notify.notified().await; + } + } + + #[allow(dead_code)] + pub fn is_closed(&self) -> bool { + self.closed.load(Ordering::Relaxed) + } + + pub async fn close(&self) { + self.closed.store(true, Ordering::Relaxed); + self.notify.notify_one(); + //wait for write to finish + let _ = self.write_semaphore.acquire().await.unwrap(); + } + + pub async fn clear(&self) { + self.closed.store(false, Ordering::Relaxed); + self.notify.notify_one(); + //wait for write to finish + let _ = self.write_semaphore.acquire().await.unwrap(); + self.len.store(0, Ordering::Relaxed); + self.inner.lock().unwrap().clear(); + self.closed.store(false, Ordering::Relaxed); + } + + pub fn read(&self, desired_size: Option) -> Option> { + let mut inner = self.inner.lock().unwrap(); + let done = self.closed.load(Ordering::Relaxed); + + let items = if done { + Some(inner.drain(0..).collect()) + } else if let Some(desired_len) = desired_size { + let max_capacity = self.max_capacity.load(Ordering::Relaxed); + if desired_len > max_capacity { + let diff = desired_len - max_capacity; + inner.reserve(diff - 1); + let mut max_capacity = inner.capacity(); + if desired_len > max_capacity { + inner.reserve(desired_len - max_capacity); + max_capacity = inner.capacity(); + } + drop(inner); + self.max_capacity.store(max_capacity, Ordering::Relaxed); + self.notify.notify_one(); + return None; + } + + let len = self.len.load(Ordering::Relaxed); + if desired_len > len { + self.notify.notify_one(); + return None; + } + + Some(inner.drain(0..desired_len).collect()) + } else { + Some(inner.drain(0..).collect()) + }; + self.len.store(inner.len(), Ordering::Relaxed); + drop(inner); + self.notify.notify_one(); + items + } +} + +#[cfg(test)] +mod tests { + use super::BytearrayBuffer; + + #[tokio::test] + async fn clear_while_writing() { + let queue = BytearrayBuffer::new(8); + let queue2 = queue.clone(); + + tokio::task::spawn(async move { + let mut vec: Vec = (0..=255).collect(); + queue.write(&mut vec).await; + }); + + queue2.clear().await + } + + #[tokio::test] + async fn write_one_at_a_time() { + let queue = BytearrayBuffer::new(8); + let queue2 = queue.clone(); + let queue3 = queue.clone(); + + tokio::task::spawn(async move { + let mut vec: Vec = (0..=127).collect(); + queue.write(&mut vec).await; + }); + + tokio::task::spawn(async move { + let mut vec: Vec = (128..=255).collect(); + queue2.write(&mut vec).await; + }); + + let mut data = Vec::::new(); + + loop { + tokio::task::yield_now().await; + if let Some(bytes) = queue3.read(Some(256)) { + data.extend(bytes); + break; + } + } + + //assert that data in vec is increment from 0 to 255 + for i in 0..=255 { + assert_eq!(data[i as usize], i); + } + } + + #[tokio::test] + async fn queue() { + let queue = BytearrayBuffer::new(8); + let queue2 = queue.clone(); + + let write_task = tokio::task::spawn(async move { + for _ in 0..=255 { + let mut vec: Vec = (0..=255).collect(); + queue.write(&mut vec).await; + } + queue.close().await; + }); + + let mut data = Vec::::new(); + + loop { + let done = queue2.is_closed(); + + tokio::task::yield_now().await; + if let Some(bytes) = queue2.read(Some(9)) { + data.extend(bytes); + } + if done { + break; + } + } + + let _ = write_task.await; + + assert_eq!(data.len(), 256 * 256) + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/bytes.rs b/host/cred-script/vendor/llrt_utils_watts/src/bytes.rs new file mode 100644 index 0000000..1e67ad0 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/bytes.rs @@ -0,0 +1,380 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use std::rc::Rc; + +use rquickjs::{ + atom::PredefinedAtom, + class::{Trace, Tracer}, + function::Constructor, + ArrayBuffer, Coerced, Ctx, Exception, FromJs, IntoJs, JsLifetime, Object, Result, TypedArray, + Value, +}; + +use crate::{error_messages::ERROR_MSG_ARRAY_BUFFER_DETACHED, result::ResultExt}; + +#[derive(Clone, PartialEq)] +pub enum ObjectBytes<'js> { + U8Array(TypedArray<'js, u8>), + I8Array(TypedArray<'js, i8>), + U16Array(TypedArray<'js, u16>), + I16Array(TypedArray<'js, i16>), + U32Array(TypedArray<'js, u32>), + I32Array(TypedArray<'js, i32>), + U64Array(TypedArray<'js, u64>), + I64Array(TypedArray<'js, i64>), + F32Array(TypedArray<'js, f32>), + F64Array(TypedArray<'js, f64>), + DataView(ArrayBuffer<'js>), + Vec(Vec), +} + +// Requires manual implementation because rquickjs hasn't implemented JsLifetime for f32 or f64 +unsafe impl<'js> JsLifetime<'js> for ObjectBytes<'js> { + type Changed<'to> = ObjectBytes<'to>; +} + +impl<'js> Trace<'js> for ObjectBytes<'js> { + fn trace<'a>(&self, tracer: Tracer<'a, 'js>) { + match self { + ObjectBytes::U8Array(a) => a.trace(tracer), + ObjectBytes::I8Array(a) => a.trace(tracer), + ObjectBytes::U16Array(a) => a.trace(tracer), + ObjectBytes::I16Array(a) => a.trace(tracer), + ObjectBytes::U32Array(a) => a.trace(tracer), + ObjectBytes::I32Array(a) => a.trace(tracer), + ObjectBytes::U64Array(a) => a.trace(tracer), + ObjectBytes::I64Array(a) => a.trace(tracer), + ObjectBytes::F32Array(a) => a.trace(tracer), + ObjectBytes::F64Array(a) => a.trace(tracer), + ObjectBytes::DataView(d) => d.trace(tracer), + ObjectBytes::Vec(v) => v.trace(tracer), + } + } +} + +impl<'js> IntoJs<'js> for ObjectBytes<'js> { + fn into_js(self, ctx: &Ctx<'js>) -> Result> { + match self { + ObjectBytes::U8Array(a) => a.into_js(ctx), + ObjectBytes::I8Array(a) => a.into_js(ctx), + ObjectBytes::U16Array(a) => a.into_js(ctx), + ObjectBytes::I16Array(a) => a.into_js(ctx), + ObjectBytes::U32Array(a) => a.into_js(ctx), + ObjectBytes::I32Array(a) => a.into_js(ctx), + ObjectBytes::U64Array(a) => a.into_js(ctx), + ObjectBytes::I64Array(a) => a.into_js(ctx), + ObjectBytes::F32Array(a) => a.into_js(ctx), + ObjectBytes::F64Array(a) => a.into_js(ctx), + ObjectBytes::DataView(d) => { + let ctor: Constructor = ctx.globals().get(PredefinedAtom::DataView)?; + ctor.construct((d,)) + }, + ObjectBytes::Vec(v) => v.into_js(ctx), + } + } +} + +impl<'js> TryFrom> for Vec { + type Error = Rc; + fn try_from(value: ObjectBytes<'js>) -> std::result::Result { + value.into_bytes_inner() + } +} + +impl<'a, 'js> TryFrom<&'a ObjectBytes<'js>> for &'a [u8] { + type Error = Rc; + fn try_from(value: &'a ObjectBytes<'js>) -> std::result::Result { + value.as_bytes_inner() + } +} + +impl<'js> FromJs<'js> for ObjectBytes<'js> { + fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + Self::from_offset(ctx, &value, 0, None) + } +} + +impl<'js> ObjectBytes<'js> { + pub fn from(ctx: &Ctx<'js>, value: &Value<'js>) -> Result { + Self::from_offset(ctx, value, 0, None) + } + + pub fn from_offset( + ctx: &Ctx<'js>, + value: &Value<'js>, + offset: usize, + length: Option, + ) -> Result { + if value.is_undefined() { + return Ok(ObjectBytes::Vec(vec![])); + } + if let Some(bytes) = get_string_bytes(value, offset, length)? { + return Ok(ObjectBytes::Vec(bytes)); + } + if let Some(bytes) = get_array_bytes(value, offset, length)? { + return Ok(ObjectBytes::Vec(bytes)); + } + + if let Some(obj) = value.as_object() { + if let Some(bytes) = Self::from_array_buffer(obj)? { + return Ok(bytes); + } + } + + if let Some(bytes) = get_coerced_string_bytes(value, offset, length) { + return Ok(ObjectBytes::Vec(bytes)); + } + + Err(Exception::throw_message( + ctx, + "value must be typed DataView, Buffer, ArrayBuffer, Uint8Array or interpretable as string", + )) + } + + pub fn as_bytes(&self, ctx: &Ctx<'js>) -> Result<&[u8]> { + self.as_bytes_inner().or_throw(ctx) + } + + fn as_bytes_inner(&self) -> std::result::Result<&[u8], Rc> { + match self { + ObjectBytes::U8Array(array) => array.as_bytes(), + ObjectBytes::I8Array(array) => array.as_bytes(), + ObjectBytes::U16Array(array) => array.as_bytes(), + ObjectBytes::I16Array(array) => array.as_bytes(), + ObjectBytes::U32Array(array) => array.as_bytes(), + ObjectBytes::I32Array(array) => array.as_bytes(), + ObjectBytes::U64Array(array) => array.as_bytes(), + ObjectBytes::I64Array(array) => array.as_bytes(), + ObjectBytes::F32Array(array) => array.as_bytes(), + ObjectBytes::F64Array(array) => array.as_bytes(), + ObjectBytes::DataView(array_buffer) => array_buffer.as_bytes(), + ObjectBytes::Vec(bytes) => Some(bytes.as_ref()), + } + .ok_or(ERROR_MSG_ARRAY_BUFFER_DETACHED.into()) + } + + pub fn into_bytes(self, ctx: &Ctx<'_>) -> Result> { + self.into_bytes_inner().or_throw(ctx) + } + + fn into_bytes_inner(self) -> std::result::Result, Rc> { + if let ObjectBytes::Vec(bytes) = self { + return Ok(bytes); + } + Ok(self.as_bytes_inner()?.to_vec()) + } + + pub fn from_array_buffer(obj: &Object<'js>) -> Result>> { + //most common + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::U8Array(typed_array))); + } + //second most common + if let Some(array_buffer) = ArrayBuffer::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::DataView(array_buffer))); + } + + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::I8Array(typed_array))); + } + + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::U16Array(typed_array))); + } + + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::I16Array(typed_array))); + } + + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::U32Array(typed_array))); + } + + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::I32Array(typed_array))); + } + + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::U64Array(typed_array))); + } + + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::I64Array(typed_array))); + } + + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::F32Array(typed_array))); + } + + if let Ok(typed_array) = TypedArray::::from_object(obj.clone()) { + return Ok(Some(ObjectBytes::F64Array(typed_array))); + } + + if let Ok(array_buffer) = obj.get::<_, ArrayBuffer>("buffer") { + return Ok(Some(ObjectBytes::DataView(array_buffer))); + } + + Ok(None) + } + + pub fn get_array_buffer(&self) -> Result, usize, usize)>> { + let buffer = match self { + ObjectBytes::DataView(array_buffer) => (array_buffer.clone(), array_buffer.len(), 0), + ObjectBytes::U8Array(typed_array) => { + let byte_length = typed_array.len(); + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + ObjectBytes::I8Array(typed_array) => { + let byte_length = typed_array.len(); + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + ObjectBytes::U16Array(typed_array) => { + let byte_length = typed_array.len() * 2; + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + ObjectBytes::I16Array(typed_array) => { + let byte_length = typed_array.len() * 2; + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + ObjectBytes::U32Array(typed_array) => { + let byte_length = typed_array.len() * 4; + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + ObjectBytes::I32Array(typed_array) => { + let byte_length = typed_array.len() * 4; + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + ObjectBytes::U64Array(typed_array) => { + let byte_length = typed_array.len() * 8; + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + ObjectBytes::I64Array(typed_array) => { + let byte_length = typed_array.len() * 8; + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + ObjectBytes::F32Array(typed_array) => { + let byte_length = typed_array.len() * 4; + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + ObjectBytes::F64Array(typed_array) => { + let byte_length = typed_array.len() * 8; + ( + typed_array.arraybuffer()?, + byte_length, + typed_array.get("byteOffset")?, + ) + }, + _ => return Ok(None), + }; + + Ok(Some(buffer)) + } +} + +pub fn get_start_end_indexes( + source_len: usize, + target_len: Option, + offset: usize, +) -> (usize, usize) { + if offset > source_len { + return (0, 0); + } + + let target_len = target_len.unwrap_or(source_len - offset); + + if offset + target_len > source_len { + return (offset, source_len); + } + + (offset, target_len + offset) +} + +pub fn get_array_bytes( + value: &Value<'_>, + offset: usize, + length: Option, +) -> Result>> { + if value.is_array() { + let array = value.as_array().unwrap(); + let (start, end) = get_start_end_indexes(array.len(), length, offset); + let size = end - start; + let mut bytes: Vec = Vec::with_capacity(size); + + for val in array.iter::().skip(start).take(size) { + let val: u8 = val?; + bytes.push(val); + } + + return Ok(Some(bytes)); + } + Ok(None) +} + +pub fn get_coerced_string_bytes( + value: &Value<'_>, + offset: usize, + length: Option, +) -> Option> { + if let Ok(val) = value.get::>() { + return Some(bytes_from_js_string(val.0, offset, length)); + }; + None +} + +fn bytes_from_js_string(string: String, offset: usize, length: Option) -> Vec { + let (start, end) = get_start_end_indexes(string.len(), length, offset); + string.as_bytes()[start..end].to_vec() +} + +#[inline] +pub fn get_string_bytes( + value: &Value<'_>, + offset: usize, + length: Option, +) -> Result>> { + if let Some(val) = value.as_string() { + let string = val.to_string()?; + return Ok(Some(bytes_from_js_string(string, offset, length))); + } + Ok(None) +} + +pub fn bytes_to_typed_array<'js>(ctx: Ctx<'js>, bytes: &[u8]) -> Result> { + TypedArray::::new(ctx.clone(), bytes).into_js(&ctx) +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/class.rs b/host/cred-script/vendor/llrt_utils_watts/src/class.rs new file mode 100644 index 0000000..e06abdb --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/class.rs @@ -0,0 +1,77 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{ + atom::PredefinedAtom, class::JsClass, object::Accessor, prelude::This, Array, Class, Ctx, + Function, Object, Result, Value, +}; + +use crate::primordials::{BasePrimordials, Primordial}; + +use super::{object::ObjectExt, result::OptionExt}; + +pub static CUSTOM_INSPECT_SYMBOL_DESCRIPTION: &str = "llrt.inspect.custom"; + +pub trait IteratorDef<'js> +where + Self: 'js + JsClass<'js> + Sized, +{ + fn js_entries(&self, ctx: Ctx<'js>) -> Result>; + + fn js_iterator(&self, ctx: Ctx<'js>) -> Result> { + let value = self.js_entries(ctx)?; + let obj = value.as_object(); + let values_fn: Function = obj.get(PredefinedAtom::Values)?; + values_fn.call((This(value),)) + } +} + +pub fn get_class_name(value: &Value) -> Result> { + value + .get_optional::<_, Object>(PredefinedAtom::Constructor)? + .and_then_ok(|ctor| ctor.get_optional::<_, String>(PredefinedAtom::Name)) +} + +#[inline(always)] +pub fn get_class<'js, C>(provided: &Value<'js>) -> Result>> +where + C: JsClass<'js>, +{ + if provided + .as_object() + .map(|p| p.instance_of::()) + .unwrap_or_default() + { + return Ok(Some(Class::::from_value(provided)?)); + } + Ok(None) +} + +pub trait CustomInspectExtension<'js> { + fn define_with_custom_inspect(globals: &Object<'js>) -> Result<()>; +} + +pub trait CustomInspect<'js> +where + Self: JsClass<'js>, +{ + fn custom_inspect(&self, ctx: Ctx<'js>) -> Result>; +} + +impl<'js, C> CustomInspectExtension<'js> for Class<'js, C> +where + C: JsClass<'js> + CustomInspect<'js> + 'js, +{ + fn define_with_custom_inspect(globals: &Object<'js>) -> Result<()> { + Self::define(globals)?; + let custom_inspect_symbol = BasePrimordials::get(globals.ctx())? + .symbol_custom_inspect + .clone(); + if let Some(proto) = Class::::prototype(globals.ctx())? { + proto.prop( + custom_inspect_symbol, + Accessor::from(|this: This>, ctx| this.borrow().custom_inspect(ctx)), + )?; + } + Ok(()) + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/clone.rs b/host/cred-script/vendor/llrt_utils_watts/src/clone.rs new file mode 100644 index 0000000..e2a1d12 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/clone.rs @@ -0,0 +1,487 @@ +use std::collections::HashSet; + +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{ + atom::PredefinedAtom, + function::{Constructor, Opt, This}, + Array, ArrayBuffer, Ctx, Exception, Function, IntoJs, Null, Object, Result, Type, Value, +}; + +use super::{ + hash, + object::ObjectExt, + primordials::{BasePrimordials, Primordial}, +}; + +#[derive(Debug)] +enum StackItem<'js> { + Value(usize, Value<'js>, Option, Option), + ObjectEnd, +} + +#[derive(Debug)] +enum ObjectType { + Set, + Map, +} + +#[derive(Debug)] +enum TapeValue<'js> { + Array(Array<'js>), + Object(Object<'js>), + Value(Value<'js>), + Collection(Option>, ObjectType), +} + +#[derive(Debug)] +struct TapeItem<'js> { + parent: usize, + object_key: Option, + array_index: Option, + value: TapeValue<'js>, +} + +pub fn structured_clone<'js>( + ctx: &Ctx<'js>, + value: Value<'js>, + options: Opt>, +) -> Result> { + let primordials = BasePrimordials::get(ctx)?; + let mut transfer_set = None; + + if let Some(options) = options.0 { + if let Some(transfer_array) = options.get_optional::<_, Array>("transfer")? { + let mut set = HashSet::with_capacity(transfer_array.len()); + + for item in transfer_array.iter::() { + set.insert(item?); + } + transfer_set = Some(set); + } + } + + let mut tape = Vec::::with_capacity(10); + let mut stack = Vec::with_capacity(10); + let mut visited = Vec::<(usize, usize)>::with_capacity(10); + let mut index = 0usize; + + stack.push(StackItem::Value(0, value, None, None)); + + while let Some(item) = stack.pop() { + match item { + StackItem::Value(parent, value, mut object_key, array_index) => { + if let Some(set) = &transfer_set { + if let Some(value) = set.get(&value) { + append_transfer_value(&mut tape, value, parent, object_key, array_index)?; + index += 1; + continue; + } + } + match value.type_of() { + Type::Proxy => { + return Err(Exception::throw_type( + ctx, + "A Proxy value could not be cloned", + )); + }, + Type::Object => { + if check_circular( + &mut tape, + &mut visited, + &value, + parent, + &mut object_key, + array_index, + index, + ) { + index += 1; + continue; + } + + //unsafe OK since we're guaranteed to be object by the match + let object = unsafe { value.as_object().unwrap_unchecked() }; + + if object.is_instance_of(&primordials.constructor_date) { + append_ctor_value( + &mut tape, + object, + &primordials.constructor_date, + parent, + object_key, + array_index, + )?; + index += 1; + continue; + } + + if object.is_instance_of(&primordials.constructor_regexp) { + append_ctor_value( + &mut tape, + object, + &primordials.constructor_regexp, + parent, + object_key, + array_index, + )?; + index += 1; + continue; + } + + let is_collection = if object.is_instance_of(&primordials.constructor_set) { + Some(ObjectType::Set) + } else if object.is_instance_of(&primordials.constructor_map) { + Some(ObjectType::Map) + } else { + None + }; + + if let Some(collection_type) = is_collection { + append_collection( + &mut tape, + &primordials.function_array_from, + object, + parent, + object_key, + array_index, + collection_type, + &mut stack, + index, + )?; + + index += 1; + continue; + } + + if primordials + .function_array_buffer_is_view + .call::<_, bool>((value.clone(),))? + { + append_buffer(&mut tape, object, parent, object_key, array_index)?; + index += 1; + continue; + } + + let new: Object<'_> = + if object.is_instance_of(&primordials.constructor_error) { + primordials.constructor_error.construct(("",)) + } else { + Object::new(ctx.clone()) + }?; + + tape.push(TapeItem { + parent, + object_key, + array_index, + value: TapeValue::Object(new), + }); + stack.push(StackItem::ObjectEnd); + + for key in object.keys::() { + let key = key?; + let value = object.get(&key)?; + stack.push(StackItem::Value(index, value, Some(key), None)); + } + }, + Type::Array => { + if check_circular( + &mut tape, + &mut visited, + &value, + parent, + &mut object_key, + array_index, + index, + ) { + index += 1; + continue; + } + let new = Array::new(ctx.clone())?; + tape.push(TapeItem { + parent, + object_key, + array_index, + value: TapeValue::Array(new), + }); + stack.push(StackItem::ObjectEnd); + //unsafe OK since we're guaranteed to be object by the match + let array = unsafe { value.as_array().unwrap_unchecked() }; + + //reverse for loop of items in array + for array_index in (0usize..array.len()).rev() { + stack.push(StackItem::Value( + index, + array.get(array_index)?, + None, + Some(array_index), + )); + } + }, + _ => { + tape.push(TapeItem { + parent, + object_key, + array_index, + value: TapeValue::Value(value), + }); + }, + } + index += 1; + }, + StackItem::ObjectEnd => { + visited.pop(); + }, + } + } + + while let Some(item) = tape.pop() { + let value = match item.value { + TapeValue::Array(array) => array.into_value(), + TapeValue::Object(object) => object.into_value(), + TapeValue::Value(value) => value, + TapeValue::Collection(mut value, _) => value.take().unwrap(), + }; + if tape.is_empty() { + return Ok(value); + } + let parent = &mut tape[item.parent]; + let array_index = item.array_index; + let object_key = item.object_key; + match &mut parent.value { + TapeValue::Array(array) => { + array.set(array_index.unwrap(), value)?; + }, + TapeValue::Object(object) => { + let string = object_key.unwrap(); + object.set(string, value)?; + }, + TapeValue::Collection(collection_value, collection_type) => { + match collection_type { + ObjectType::Set => { + collection_value.replace(primordials.constructor_set.construct((value,))?); + }, + ObjectType::Map => { + collection_value.replace(primordials.constructor_map.construct((value,))?); + }, + }; + }, + _ => {}, + }; + } + + Null.into_js(ctx) +} + +#[inline(always)] +#[cold] +fn append_buffer<'js>( + tape: &mut Vec>, + object: &Object<'js>, + parent: usize, + object_key: Option, + array_index: Option, +) -> Result<()> { + let ctor: Constructor = object.get(PredefinedAtom::Constructor)?; + let slice: Function = object.get("slice")?; + let clone: Value = slice.call((This(object.clone()),))?; + let new = ctor.construct((clone,))?; + tape.push(TapeItem { + parent, + object_key, + array_index, + value: TapeValue::Value(new), + }); + Ok(()) +} + +#[inline(always)] +#[cold] +#[allow(clippy::too_many_arguments)] +fn append_collection<'js>( + tape: &mut Vec>, + array_from: &Function<'js>, + object: &Object<'js>, + parent: usize, + object_key: Option, + array_index: Option, + collection_type: ObjectType, + stack: &mut Vec>, + index: usize, +) -> Result<()> { + let array: Array = array_from.call((object.clone(),))?; + tape.push(TapeItem { + parent, + object_key, + array_index, + value: TapeValue::Collection(None, collection_type), + }); + stack.push(StackItem::ObjectEnd); + stack.push(StackItem::Value(index, array.into(), None, None)); + Ok(()) +} + +#[inline(always)] +fn check_circular( + tape: &mut Vec, + visited: &mut Vec<(usize, usize)>, + value: &Value<'_>, + parent: usize, + object_key: &mut Option, + array_index: Option, + index: usize, +) -> bool { + let hash = hash::default_hash(value); + if let Some(visited) = visited.iter().find(|v| v.0 == hash) { + append_circular(tape, visited, object_key, parent, array_index); + return true; + } + visited.push((hash, index)); + false +} + +#[inline(always)] +#[cold] +fn append_transfer_value<'js>( + tape: &mut Vec>, + value: &Value<'js>, + parent: usize, + object_key: Option, + array_index: Option, +) -> Result<()> { + let value = if let Some(ab) = ArrayBuffer::from_value(value.clone()) { + ab.get::<_, Function>("transfer")?.call((This(ab),))? + } else { + value.clone() + }; + + tape.push(TapeItem { + parent, + object_key, + array_index, + value: TapeValue::Value(value), + }); + Ok(()) +} + +#[inline(always)] +#[cold] +fn append_circular( + tape: &mut Vec>, + visited: &(usize, usize), + object_key: &mut Option, + parent: usize, + array_index: Option, +) { + let value = match &tape[visited.1].value { + TapeValue::Array(array) => array.clone().into_value(), + TapeValue::Object(object) => object.clone().into_value(), + TapeValue::Value(value) => value.clone(), + TapeValue::Collection(value, _) => value.clone().unwrap(), + }; + + let object_key = object_key.take(); + + tape.push(TapeItem { + parent, + object_key, + array_index, + value: TapeValue::Value(value), + }); +} + +#[inline(always)] +#[cold] +fn append_ctor_value<'js>( + tape: &mut Vec>, + object: &Object<'js>, + ctor: &Constructor<'js>, + parent: usize, + object_key: Option, + array_index: Option, +) -> Result<()> { + let clone: Value = ctor.construct((object.clone(),))?; + tape.push(TapeItem { + parent, + object_key, + array_index, + value: TapeValue::Value(clone), + }); + Ok(()) +} + +#[cfg(test)] +mod tests { + + use llrt_test::test_sync_with; + use rquickjs::{function::Opt, Object, Value}; + + use crate::primordials::{BasePrimordials, Primordial}; + + use super::structured_clone; + + #[tokio::test] + async fn clone() { + test_sync_with(|ctx| { + BasePrimordials::init(&ctx)?; + let value: Object = ctx.eval( + r#" +const a = { + "foo":{ + "bar":"baz" + }, + "foo1":{ + "bar1":"baz1", + "bar11":"baz11" + } +}; +a +"#, + )?; + + let cloned = structured_clone(&ctx, value.clone().into_value(), Opt(None))? + .into_object() + .unwrap(); + + let json = ctx + .json_stringify(value.clone())? + .unwrap() + .to_string()? + .to_string(); + + let clone_json = ctx + .json_stringify(cloned.clone())? + .unwrap() + .to_string()? + .to_string(); + + assert_eq!(json, clone_json); + + assert_ne!( + value.get::<_, Value>("foo")?, + cloned.get::<_, Value>("foo")? + ); + + Ok(()) + }) + .await + } + + #[tokio::test] + async fn clone_circular() { + test_sync_with(|ctx| { + BasePrimordials::init(&ctx)?; + let _value: Object = ctx.eval( + r#" +const originalObject = { foo: { bar: "baz",arr: [1,2,3] } }; +originalObject.foo.circularRef = originalObject; +originalObject.foo.circularRef2 = originalObject; +originalObject.foo.circularRef3 = originalObject.foo; +originalObject.ref2 = originalObject; +"#, + )?; + + Ok(()) + }) + .await + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/ctx.rs b/host/cred-script/vendor/llrt_utils_watts/src/ctx.rs new file mode 100644 index 0000000..9187167 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/ctx.rs @@ -0,0 +1,17 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{Ctx, Result}; + +pub trait CtxExt { + fn get_script_or_module_name(&self) -> Result; +} + +impl CtxExt for Ctx<'_> { + fn get_script_or_module_name(&self) -> Result { + if let Some(name) = self.script_or_module_name(0) { + name.to_string() + } else { + Ok(String::from(".")) + } + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/error.rs b/host/cred-script/vendor/llrt_utils_watts/src/error.rs new file mode 100644 index 0000000..d9e9fb3 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/error.rs @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{CatchResultExt, CaughtError, Ctx, Error, IntoJs, Result, Value}; + +pub trait ErrorExtensions<'js> { + fn into_value(self, ctx: &Ctx<'js>) -> Result>; +} + +impl<'js> ErrorExtensions<'js> for Error { + fn into_value(self, ctx: &Ctx<'js>) -> Result> { + Err::<(), _>(self).catch(ctx).unwrap_err().into_value(ctx) + } +} + +impl<'js> ErrorExtensions<'js> for CaughtError<'js> { + fn into_value(self, ctx: &Ctx<'js>) -> Result> { + Ok(match self { + CaughtError::Error(err) => err.to_string().into_js(ctx)?, + CaughtError::Exception(ex) => ex.into_value(), + CaughtError::Value(val) => val, + }) + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/error_messages.rs b/host/cred-script/vendor/llrt_utils_watts/src/error_messages.rs new file mode 100644 index 0000000..386c741 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/error_messages.rs @@ -0,0 +1,3 @@ +pub const ERROR_MSG_NOT_ARRAY_BUFFER: &str = "Not an ArrayBuffer"; +pub const ERROR_MSG_ARRAY_BUFFER_DETACHED: &str = "ArrayBuffer is detached"; +pub const ERROR_MSG_BROADCAST_LAGGED: &str = "Lagged too much behind"; diff --git a/host/cred-script/vendor/llrt_utils_watts/src/fs.rs b/host/cred-script/vendor/llrt_utils_watts/src/fs.rs new file mode 100644 index 0000000..0225453 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/fs.rs @@ -0,0 +1,103 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use std::{fs::Metadata, io, path::PathBuf}; + +use tokio::fs::{self}; + +pub struct DirectoryWalker +where + T: Fn(&str) -> bool, +{ + stack: Vec<(PathBuf, Option)>, + filter: T, + recursive: bool, + eat_root: bool, +} + +impl DirectoryWalker +where + T: Fn(&str) -> bool, +{ + pub fn new(root: PathBuf, filter: T) -> Self { + Self { + stack: vec![(root, None)], + filter, + recursive: false, + eat_root: true, + } + } + + pub fn set_recursive(&mut self, recursive: bool) { + self.recursive = recursive; + } + + pub async fn walk(&mut self) -> io::Result> { + if self.eat_root { + self.eat_root = false; + let (dir, _) = self.stack.pop().unwrap(); + self.append_stack(&dir).await?; + } + if let Some((entry, metadata)) = self.stack.pop() { + let metadata = metadata.unwrap(); + if self.recursive && metadata.is_dir() { + self.append_stack(&entry).await?; + } + + Ok(Some((entry, metadata))) + } else { + Ok(None) + } + } + + pub fn walk_sync(&mut self) -> io::Result> { + if self.eat_root { + self.eat_root = false; + let (dir, _) = self.stack.pop().unwrap(); + self.append_stack_sync(&dir)?; + } + if let Some((entry, metadata)) = self.stack.pop() { + let metadata = metadata.unwrap(); + if self.recursive && metadata.is_dir() { + self.append_stack_sync(&entry)?; + } + + Ok(Some((entry, metadata))) + } else { + Ok(None) + } + } + + async fn append_stack(&mut self, dir: &PathBuf) -> io::Result<()> { + let mut stream = fs::read_dir(dir).await?; + + while let Some(entry) = stream.next_entry().await? { + let name = entry.file_name(); + let name = name.to_string_lossy(); + if !(self.filter)(name.as_ref()) { + continue; + } + let entry_path = entry.path(); + let metadata = fs::symlink_metadata(&entry_path).await?; + + self.stack.push((entry_path, Some(metadata))); + } + Ok(()) + } + + fn append_stack_sync(&mut self, dir: &PathBuf) -> io::Result<()> { + let dir = std::fs::read_dir(dir)?; + + for entry in dir.flatten() { + let name = entry.file_name(); + let name = name.to_string_lossy(); + if !(self.filter)(name.as_ref()) { + continue; + } + let entry_path = entry.path(); + let metadata = entry_path.symlink_metadata()?; + self.stack.push((entry_path, Some(metadata))) + } + + Ok(()) + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/hash.rs b/host/cred-script/vendor/llrt_utils_watts/src/hash.rs new file mode 100644 index 0000000..320a465 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/hash.rs @@ -0,0 +1,8 @@ +use std::hash::{DefaultHasher, Hash, Hasher}; + +#[inline] +pub fn default_hash(v: &T) -> usize { + let mut state = DefaultHasher::default(); + v.hash(&mut state); + state.finish() as usize +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/io.rs b/host/cred-script/vendor/llrt_utils_watts/src/io.rs new file mode 100644 index 0000000..d1aa9d6 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/io.rs @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +macro_rules! define_extension { + ($base:ident, $file:ident, $ext:expr) => { + #[allow(dead_code)] + pub const $base: &str = $ext; + #[allow(dead_code)] + pub const $file: &str = concat!(".", $ext); + }; +} + +define_extension!(BYTECODE_EXT, BYTECODE_FILE_EXT, "lrt"); + +macro_rules! define_supported_extensions { + // Accepts a list of supported extensions and a single additional constant extension + ($constant_ext:ident, $($ext:literal),*) => { + // Define the array of extensions as a constant + pub const SUPPORTED_EXTENSIONS: &[&str] = &[$($ext),*, $constant_ext]; + + pub const JS_EXTENSIONS: &[&str] = &[$($ext),*]; + + // Define the function `is_supported_ext` using a match statement + pub fn is_supported_ext(ext: &str) -> bool { + matches!(ext, $($ext)|* | $constant_ext) + } + }; +} + +define_supported_extensions!(BYTECODE_FILE_EXT, ".js", ".mjs", ".cjs"); diff --git a/host/cred-script/vendor/llrt_utils_watts/src/latch.rs b/host/cred-script/vendor/llrt_utils_watts/src/latch.rs new file mode 100644 index 0000000..fa2296d --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/latch.rs @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use std::sync::atomic::{AtomicUsize, Ordering}; + +use tokio::sync::Notify; + +#[derive(Default)] +pub struct Latch { + count: AtomicUsize, + notify: Notify, +} + +impl Latch { + pub fn increment(&self) { + self.count.fetch_add(1, Ordering::Relaxed); + } + + pub fn decrement(&self) { + let previous = self.count.fetch_sub(1, Ordering::Relaxed); + if previous == 1 { + self.notify.notify_waiters(); + } + } + + pub async fn wait(&self) { + if self.count.load(Ordering::Relaxed) > 0 { + self.notify.notified().await; + } + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/lib.rs b/host/cred-script/vendor/llrt_utils_watts/src/lib.rs new file mode 100644 index 0000000..cccde27 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/lib.rs @@ -0,0 +1,33 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +pub mod any_of; +#[cfg(feature = "bytearray-buffer")] +pub mod bytearray_buffer; +pub mod bytes; +pub mod class; +pub mod clone; +pub mod ctx; +pub mod error; +pub mod error_messages; +#[cfg(feature = "fs")] +pub mod fs; +pub mod hash; +pub mod io; +pub mod latch; +pub mod macros; +pub mod mc_oneshot; +pub mod module; +pub mod object; +pub mod option; +pub mod primordials; +pub mod provider; +pub mod result; +pub mod reuse_list; +pub mod string; +pub mod sysinfo; +pub mod time; + +#[cfg(any(unix, windows))] +pub mod signals; + +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/host/cred-script/vendor/llrt_utils_watts/src/macros.rs b/host/cred-script/vendor/llrt_utils_watts/src/macros.rs new file mode 100644 index 0000000..36c33ee --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/macros.rs @@ -0,0 +1,55 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +#[macro_export] +macro_rules! count_members { + () => (0); + ($head:tt $(,$tail:tt)*) => (1 + count_members!($($tail),*)); +} + +#[macro_export] +macro_rules! iterable_enum { + ($name:ident, $($variant:ident),*) => { + impl $name { + const VARIANTS: &'static [$name] = &[$($name::$variant,)*]; + pub fn iter() -> std::slice::Iter<'static, $name> { + Self::VARIANTS.iter() + } + + #[allow(dead_code)] + fn _ensure_all_variants(s: Self) { + match s { + $($name::$variant => {},)* + } + } + } + }; +} + +#[macro_export] +macro_rules! str_enum { + ($name:ident, $($variant:ident => $str:expr),*) => { + impl $name { + pub fn as_str(&self) -> &'static str { + match self { + $($name::$variant => $str,)* + } + } + } + + impl AsRef for $name { + fn as_ref(&self) -> &str { + self.as_str() + } + } + + impl TryFrom<&str> for $name { + type Error = String; + fn try_from(s: &str) -> std::result::Result { + match s { + $($str => Ok($name::$variant),)* + _ => Err(["'", s, "' not available"].concat()) + } + } + } + }; +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/mc_oneshot.rs b/host/cred-script/vendor/llrt_utils_watts/src/mc_oneshot.rs new file mode 100644 index 0000000..dea1081 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/mc_oneshot.rs @@ -0,0 +1,118 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, RwLock, +}; + +use rquickjs::{ + class::{Trace, Tracer}, + Value, +}; +use std::ops::Deref; +use tokio::sync::Notify; + +#[derive(Debug)] +pub struct Shared { + is_sent: AtomicBool, + value: RwLock>, + notify: Notify, +} + +#[derive(Clone, Debug)] +pub struct Sender(Arc>); + +impl Deref for Sender { + type Target = Arc>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'js> Trace<'js> for Sender> { + fn trace<'a>(&self, tracer: Tracer<'a, 'js>) { + if let Ok(v) = self.value.read() { + if let Some(v) = v.as_ref() { + tracer.mark(v) + } + } + } +} + +impl Sender { + pub fn send(&self, value: T) { + if !self.is_sent.load(Ordering::Relaxed) { + self.value.write().unwrap().replace(value); + self.is_sent.store(true, Ordering::Release); + self.notify.notify_waiters(); + } + } + + pub fn subscribe(&self) -> Receiver { + Receiver(Arc::clone(&self.0)) + } +} + +#[derive(Clone, Debug)] +pub struct Receiver(Arc>); + +impl Deref for Receiver { + type Target = Arc>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Receiver { + pub async fn recv(&self) -> T { + if !self.is_sent.load(Ordering::Acquire) { + self.notify.notified().await; + } + self.value.read().unwrap().clone().unwrap() + } +} + +pub fn channel() -> (Sender, Receiver) { + let shared = Arc::new(Shared { + is_sent: AtomicBool::new(false), + value: RwLock::new(None), + notify: Notify::new(), + }); + + (Sender(Arc::clone(&shared)), Receiver(shared)) +} + +#[cfg(test)] +mod tests { + use tokio::join; + + #[tokio::test] + async fn test() { + let (tx, rx1) = super::channel::(); + + let rx2 = tx.subscribe(); + let rx3 = tx.subscribe(); + + let a = tokio::spawn(async move { + let val = rx1.recv().await; //wait for value to become false + assert!(val) + }); + + let b = tokio::spawn(async move { + let val = rx2.recv().await; //wait for value to become false + assert!(val) + }); + + tokio::time::sleep(std::time::Duration::from_millis(10)).await; + + tx.send(true); + + let val = rx3.recv().await; + assert!(val); + + let (a, b) = join!(a, b); + a.unwrap(); + b.unwrap(); + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/module.rs b/host/cred-script/vendor/llrt_utils_watts/src/module.rs new file mode 100644 index 0000000..90ea3d6 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/module.rs @@ -0,0 +1,29 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{ + module::{Exports, ModuleDef}, + Ctx, Object, Result, Value, +}; + +pub struct ModuleInfo { + pub name: &'static str, + pub module: T, +} + +pub fn export_default<'js, F>(ctx: &Ctx<'js>, exports: &Exports<'js>, f: F) -> Result<()> +where + F: FnOnce(&Object<'js>) -> Result<()>, +{ + let default = Object::new(ctx.clone())?; + f(&default)?; + + for name in default.keys::() { + let name = name?; + let value: Value = default.get(&name)?; + exports.export(name, value)?; + } + + exports.export("default", default)?; + + Ok(()) +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/object.rs b/host/cred-script/vendor/llrt_utils_watts/src/object.rs new file mode 100644 index 0000000..99a93aa --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/object.rs @@ -0,0 +1,176 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use std::collections::BTreeMap; + +use rquickjs::{ + atom::PredefinedAtom, function::IntoJsFunc, prelude::Func, Array, Coerced, Ctx, Error, + Exception, FromJs, IntoAtom, IntoJs, Object, Result, Symbol, Undefined, Value, +}; + +use crate::primordials::{BasePrimordials, Primordial}; + +pub trait ObjectExt<'js> { + fn get_optional + Clone, V: FromJs<'js>>(&self, k: K) -> Result>; + fn get_required, V: FromJs<'js>>( + &self, + k: K, + object_name: &'static str, + ) -> Result; + fn into_object_or_throw(self, ctx: &Ctx<'js>, object_name: &'static str) + -> Result>; +} + +impl<'js> ObjectExt<'js> for Object<'js> { + fn get_optional + Clone, V: FromJs<'js> + Sized>( + &self, + k: K, + ) -> Result> { + self.get::>(k) + } + + fn get_required, V: FromJs<'js>>( + &self, + k: K, + object_name: &'static str, + ) -> Result { + let k = k.as_ref(); + self.get::<&str, Option>(k)?.ok_or_else(|| { + Exception::throw_type( + self.ctx(), + &[object_name, " '", k, "' property required"].concat(), + ) + }) + } + + fn into_object_or_throw(self, _: &Ctx<'js>, _: &'static str) -> Result> { + Ok(self) + } +} + +impl<'js> ObjectExt<'js> for Value<'js> { + fn get_optional + Clone, V: FromJs<'js>>(&self, k: K) -> Result> { + if let Some(obj) = self.as_object() { + return obj.get_optional(k); + } + Ok(None) + } + + fn get_required, V: FromJs<'js>>( + &self, + k: K, + object_name: &'static str, + ) -> Result { + self.as_object() + .ok_or_else(|| not_a_object_error(self.ctx(), object_name))? + .get_required(k, object_name) + } + + fn into_object_or_throw( + self, + ctx: &Ctx<'js>, + object_name: &'static str, + ) -> Result> { + self.into_object() + .ok_or_else(|| not_a_object_error(ctx, object_name)) + } +} + +pub fn not_a_object_error(ctx: &Ctx<'_>, object_name: &str) -> Error { + Exception::throw_type(ctx, &[object_name, " is not an object"].concat()) +} + +pub trait CreateSymbol<'js> { + fn for_description(ctx: &Ctx<'js>, description: &str) -> Result>; +} + +impl<'js> CreateSymbol<'js> for Symbol<'js> { + fn for_description(ctx: &Ctx<'js>, description: &str) -> Result> { + BasePrimordials::get(ctx)? + .function_symbol_for + .call((description,)) + } +} + +pub struct Proxy<'js> { + target: Value<'js>, + options: Object<'js>, +} + +impl<'js> IntoJs<'js> for Proxy<'js> { + fn into_js(self, ctx: &Ctx<'js>) -> Result> { + BasePrimordials::get(ctx)? + .constructor_proxy + .construct::<_, Value>((self.target, self.options)) + } +} + +impl<'js> Proxy<'js> { + pub fn new(ctx: Ctx<'js>) -> Result { + let options = Object::new(ctx.clone())?; + Ok(Self { + target: Undefined.into_value(ctx), + options, + }) + } + + pub fn with_target(ctx: Ctx<'js>, target: Value<'js>) -> Result { + let options = Object::new(ctx)?; + Ok(Self { target, options }) + } + + pub fn setter(&self, setter: Func) -> Result<()> + where + T: IntoJsFunc<'js, P> + 'js, + { + self.options.set(PredefinedAtom::Setter, setter)?; + Ok(()) + } + + pub fn getter(&self, getter: Func) -> Result<()> + where + T: IntoJsFunc<'js, P> + 'js, + { + self.options.set(PredefinedAtom::Getter, getter)?; + Ok(()) + } +} + +pub fn map_to_entries<'js, K, V, M>(ctx: &Ctx<'js>, map: M) -> Result> +where + M: IntoIterator, + K: IntoJs<'js>, + V: IntoJs<'js>, +{ + let array = Array::new(ctx.clone())?; + for (idx, (key, value)) in map.into_iter().enumerate() { + let entry = Array::new(ctx.clone())?; + entry.set(0, key)?; + entry.set(1, value)?; + array.set(idx, entry)?; + } + + Ok(array) +} + +pub fn array_to_btree_map<'js>( + ctx: &Ctx<'js>, + array: Array<'js>, +) -> Result>> { + let value = object_from_entries(ctx, array)?; + let value = value.into_value(); + BTreeMap::from_js(ctx, value) +} + +pub fn object_from_entries<'js>(ctx: &Ctx<'js>, array: Array<'js>) -> Result> { + let obj = Object::new(ctx.clone())?; + for value in array.into_iter().flatten() { + if let Some(entry) = value.as_array() { + if let Ok(key) = entry.get::(0) { + if let Ok(value) = entry.get::(1) { + let _ = obj.set(key, value); //ignore result of failed + } + } + } + } + Ok(obj) +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/option.rs b/host/cred-script/vendor/llrt_utils_watts/src/option.rs new file mode 100644 index 0000000..04832fc --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/option.rs @@ -0,0 +1,101 @@ +use rquickjs::{ + class::{Trace, Tracer}, + function::{FromParam, ParamRequirement, ParamsAccessor}, + Ctx, FromJs, IntoJs, JsLifetime, Result, Type, Value, +}; + +/// Helper type for treating an undefined value as None, without treating null as None +#[derive(Clone)] +pub struct Undefined(pub Option); + +impl<'js, T: FromJs<'js>> FromJs<'js> for Undefined { + fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + if value.type_of() == Type::Undefined { + Ok(Self(None)) + } else { + Ok(Self(Some(FromJs::from_js(ctx, value)?))) + } + } +} + +impl<'js, T: IntoJs<'js>> IntoJs<'js> for Undefined { + fn into_js(self, ctx: &Ctx<'js>) -> Result> { + match self.0 { + None => Ok(Value::new_undefined(ctx.clone())), + Some(val) => val.into_js(ctx), + } + } +} + +impl Default for Undefined { + fn default() -> Self { + Self(None) + } +} + +unsafe impl<'js, T: JsLifetime<'js>> JsLifetime<'js> for Undefined { + type Changed<'to> = Undefined>; +} + +impl<'js, T: Trace<'js>> Trace<'js> for Undefined { + fn trace<'a>(&self, tracer: Tracer<'a, 'js>) { + self.0.trace(tracer) + } +} + +/// Helper type for converting an None into null instead of undefined. +/// Needed while rquickjs::function::Null has no IntoJs implementation +#[derive(Clone)] +pub struct Null(pub Option); + +impl<'js, T: FromJs<'js>> FromJs<'js> for Null { + fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + if value.type_of() == Type::Null { + Ok(Self(None)) + } else { + Ok(Self(Some(FromJs::from_js(ctx, value)?))) + } + } +} + +impl<'js, T: IntoJs<'js>> IntoJs<'js> for Null { + fn into_js(self, ctx: &Ctx<'js>) -> Result> { + match self.0 { + None => Ok(Value::new_null(ctx.clone())), + Some(val) => val.into_js(ctx), + } + } +} + +unsafe impl<'js, T: JsLifetime<'js>> JsLifetime<'js> for Null { + type Changed<'to> = Null>; +} + +impl<'js, T: Trace<'js>> Trace<'js> for Null { + fn trace<'a>(&self, tracer: Tracer<'a, 'js>) { + self.0.trace(tracer) + } +} + +/// Helper type for accepting no value, or null, but considering undefined as a value +pub struct NullableOpt(pub Option); + +impl<'js, T: FromJs<'js>> FromParam<'js> for NullableOpt { + fn param_requirement() -> ParamRequirement { + ParamRequirement::optional() + } + + fn from_param<'a>(params: &mut ParamsAccessor<'a, 'js>) -> Result { + if !params.is_empty() { + let arg = params.arg(); + if arg.is_null() { + Ok(NullableOpt(None)) + } else { + let ctx = params.ctx().clone(); + Ok(NullableOpt(Some(T::from_js(&ctx, arg)?))) + } + } else { + Ok(NullableOpt(None)) + } + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/primordials.rs b/host/cred-script/vendor/llrt_utils_watts/src/primordials.rs new file mode 100644 index 0000000..e2485c0 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/primordials.rs @@ -0,0 +1,159 @@ +use std::any::type_name; + +use rquickjs::{ + atom::PredefinedAtom, function::Constructor, runtime::UserDataGuard, Ctx, Function, JsLifetime, + Object, Result, Symbol, +}; + +use crate::{class::CUSTOM_INSPECT_SYMBOL_DESCRIPTION, result::ResultExt}; + +#[derive(JsLifetime)] +pub struct BasePrimordials<'js> { + // Constructors + pub constructor_map: Constructor<'js>, + pub constructor_set: Constructor<'js>, + pub constructor_date: Constructor<'js>, + pub constructor_error: Constructor<'js>, + pub constructor_type_error: Constructor<'js>, + pub constructor_range_error: Constructor<'js>, + pub constructor_regexp: Constructor<'js>, + pub constructor_uint8array: Constructor<'js>, + pub constructor_array_buffer: Constructor<'js>, + pub constructor_proxy: Constructor<'js>, + pub constructor_object: Constructor<'js>, + pub constructor_bool: Constructor<'js>, + pub constructor_number: Constructor<'js>, + pub constructor_string: Constructor<'js>, + + // Prototypes + pub prototype_object: Object<'js>, + pub prototype_date: Object<'js>, + pub prototype_regexp: Object<'js>, + pub prototype_set: Object<'js>, + pub prototype_map: Object<'js>, + pub prototype_error: Object<'js>, + + // Functions + pub function_array_from: Function<'js>, + pub function_array_buffer_is_view: Function<'js>, + pub function_get_own_property_descriptor: Function<'js>, + pub function_parse_int: Function<'js>, + pub function_parse_float: Function<'js>, + pub function_symbol_for: Function<'js>, + + // Symbols + pub symbol_custom_inspect: Symbol<'js>, +} + +pub trait Primordial<'js> +where + Self: Sized + JsLifetime<'js>, +{ + fn get<'a>(ctx: &'a Ctx<'js>) -> Result> { + let userdata = ctx.userdata::().or_throw_msg( + ctx, + &[ + "Userdata of ", + type_name::(), + " not initialized. Call init(&ctx) on this type.", + ] + .concat(), + )?; + + Ok(userdata) + } + + fn init<'a>(ctx: &'a Ctx<'js>) -> Result<()> { + if ctx.userdata::().is_none() { + let primoridals = Self::new(ctx)?; + let _ = ctx.store_userdata(primoridals); + } + + Ok(()) + } + fn new(ctx: &Ctx<'js>) -> Result; +} + +impl<'js> Primordial<'js> for BasePrimordials<'js> { + fn new(ctx: &Ctx<'js>) -> Result { + let globals = ctx.globals(); + + let constructor_object: Constructor = globals.get(PredefinedAtom::Object)?; + let prototype_object: Object = constructor_object.get(PredefinedAtom::Prototype)?; + + let constructor_proxy: Constructor = globals.get(PredefinedAtom::Proxy)?; + + let function_get_own_property_descriptor: Function = + constructor_object.get(PredefinedAtom::GetOwnPropertyDescriptor)?; + + let constructor_date: Constructor = globals.get(PredefinedAtom::Date)?; + let prototype_date: Object = constructor_date.get(PredefinedAtom::Prototype)?; + + let constructor_map: Constructor = globals.get(PredefinedAtom::Map)?; + let prototype_map: Object = constructor_map.get(PredefinedAtom::Prototype)?; + + let constructor_set: Constructor = globals.get(PredefinedAtom::Set)?; + let prototype_set: Object = constructor_set.get(PredefinedAtom::Prototype)?; + + let constructor_regexp: Constructor = globals.get(PredefinedAtom::RegExp)?; + let prototype_regexp: Object = constructor_regexp.get(PredefinedAtom::Prototype)?; + + let constructor_uint8array: Constructor = globals.get(PredefinedAtom::Uint8Array)?; + let constructor_arraybuffer: Constructor = globals.get(PredefinedAtom::ArrayBuffer)?; + + let constructor_error: Constructor = globals.get(PredefinedAtom::Error)?; + let constructor_type_error: Constructor = ctx.globals().get(PredefinedAtom::TypeError)?; + let constructor_range_error: Constructor = ctx.globals().get(PredefinedAtom::RangeError)?; + let prototype_error: Object = constructor_error.get(PredefinedAtom::Prototype)?; + + let constructor_array: Object = globals.get(PredefinedAtom::Array)?; + let function_array_from: Function = constructor_array.get(PredefinedAtom::From)?; + + let constructor_array_buffer: Object = globals.get(PredefinedAtom::ArrayBuffer)?; + let function_array_buffer_is_view: Function = constructor_array_buffer.get("isView")?; + + let constructor_bool: Constructor = globals.get(PredefinedAtom::Boolean)?; + + let constructor_number: Constructor = globals.get(PredefinedAtom::Number)?; + let function_parse_float: Function = constructor_number.get("parseFloat")?; + let function_parse_int: Function = constructor_number.get("parseInt")?; + + let constructor_string: Constructor = globals.get(PredefinedAtom::String)?; + + let constructor_symbol: Constructor = globals.get(PredefinedAtom::Symbol)?; + let function_symbol_for: Function = constructor_symbol.get(PredefinedAtom::For)?; + + let symbol_custom_inspect: Symbol<'js> = + function_symbol_for.call((CUSTOM_INSPECT_SYMBOL_DESCRIPTION,))?; + + Ok(Self { + constructor_map, + constructor_set, + constructor_date, + constructor_proxy, + constructor_error, + constructor_type_error, + constructor_range_error, + constructor_regexp, + constructor_uint8array, + constructor_array_buffer: constructor_arraybuffer, + constructor_object, + constructor_bool, + constructor_number, + constructor_string, + prototype_object, + prototype_date, + prototype_regexp, + prototype_set, + prototype_map, + prototype_error, + function_array_from, + function_array_buffer_is_view, + function_get_own_property_descriptor, + function_parse_float, + function_parse_int, + function_symbol_for, + symbol_custom_inspect, + }) + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/provider.rs b/host/cred-script/vendor/llrt_utils_watts/src/provider.rs new file mode 100644 index 0000000..4d9de5b --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/provider.rs @@ -0,0 +1,24 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +#[derive(PartialEq)] +pub enum ProviderType { + None, + Resource(String), // Custom asynchronous resource + // Userland provider types + Immediate, // [Immediate] Processing by setImmediate() + Interval, // [Interval] Timer by setInterval() + MessagePort, // [MessagePort] Port for worker_threads + Microtask, // [Microtask] Processing by queueMicrotask() + TickObject, // [TickObject] Processing by process.nextTick() + Timeout, // [Timeout] Timer by setTimeout() + // Internal provider types + FsReqCallback, // [FSREQCALLBACK] Callback for file system operations + GetAddrInfoReqWrap, // [GETADDRINFOREQWRAP] When resolving DNS (dns.lookup(), etc.) + GetNameInfoReqWrap, // [GETNAMEINFOREQWRAP] DNS reverse lookup + PipeWrap, // [PIPEWRAP] Pipe connection + StatWatcher, // [STATWACHER] File monitoring such as fs.watch() + TcpWrap, // [TCPWRAP] TCP socket wrap (net.Socket, etc.) + TimerWrap, // [TIMERWRAP] Internal timer wrap (low level) + TlsWrap, // [TLSWRAP] TLS socket (HTTPS, etc.) + UdpWrap, // [UDPWRAP] UDP socket wrap (dgram module) +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/result.rs b/host/cred-script/vendor/llrt_utils_watts/src/result.rs new file mode 100644 index 0000000..23754f2 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/result.rs @@ -0,0 +1,104 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +#![allow(clippy::uninlined_format_args)] + +use std::{fmt::Write, result::Result as StdResult}; + +use rquickjs::{Ctx, Exception, Result}; + +pub trait ResultExt { + fn or_throw_msg(self, ctx: &Ctx, msg: &str) -> Result; + fn or_throw_range(self, ctx: &Ctx, msg: &str) -> Result; + fn or_throw_type(self, ctx: &Ctx, msg: &str) -> Result; + fn or_throw(self, ctx: &Ctx) -> Result; +} + +pub trait OptionExt { + fn and_then_ok(self, f: F) -> StdResult, E> + where + F: FnOnce(T) -> StdResult, E>; + + fn unwrap_or_else_ok(self, f: F) -> StdResult + where + F: FnOnce() -> StdResult; +} + +impl ResultExt for StdResult { + fn or_throw_msg(self, ctx: &Ctx, msg: &str) -> Result { + self.map_err(|e| { + let mut message = String::with_capacity(100); + message.push_str(msg); + message.push_str(". "); + write!(message, "{}", e).unwrap(); + Exception::throw_message(ctx, &message) + }) + } + + fn or_throw_range(self, ctx: &Ctx, msg: &str) -> Result { + self.map_err(|e| { + let mut message = String::with_capacity(100); + if !message.is_empty() { + message.push_str(msg); + message.push_str(". "); + } + write!(message, "{}", e).unwrap(); + Exception::throw_range(ctx, &message) + }) + } + + fn or_throw_type(self, ctx: &Ctx, msg: &str) -> Result { + self.map_err(|e| { + let mut message = String::with_capacity(100); + if !msg.is_empty() { + message.push_str(msg); + message.push_str(". "); + } + write!(message, "{}", e).unwrap(); + Exception::throw_type(ctx, &message) + }) + } + + fn or_throw(self, ctx: &Ctx) -> Result { + self.map_err(|err| Exception::throw_message(ctx, &err.to_string())) + } +} + +impl ResultExt for Option { + fn or_throw_msg(self, ctx: &Ctx, msg: &str) -> Result { + self.ok_or_else(|| Exception::throw_message(ctx, msg)) + } + + fn or_throw_range(self, ctx: &Ctx, msg: &str) -> Result { + self.ok_or_else(|| Exception::throw_range(ctx, msg)) + } + + fn or_throw_type(self, ctx: &Ctx, msg: &str) -> Result { + self.ok_or_else(|| Exception::throw_type(ctx, msg)) + } + + fn or_throw(self, ctx: &Ctx) -> Result { + self.ok_or_else(|| Exception::throw_message(ctx, "Value is not present")) + } +} + +impl OptionExt for Option { + fn and_then_ok(self, f: F) -> StdResult, E> + where + F: FnOnce(T) -> StdResult, E>, + { + match self { + Some(v) => f(v), + None => Ok(None), + } + } + + fn unwrap_or_else_ok(self, f: F) -> StdResult + where + F: FnOnce() -> StdResult, + { + match self { + Some(v) => Ok(v), + None => f(), + } + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/reuse_list.rs b/host/cred-script/vendor/llrt_utils_watts/src/reuse_list.rs new file mode 100644 index 0000000..a0105d5 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/reuse_list.rs @@ -0,0 +1,337 @@ +use std::fmt::Debug; + +#[derive(Default, Clone)] +pub struct ReuseList { + items: Vec>, + slots: Vec, + last_slot_idx: usize, + len: usize, + slot_size: usize, +} + +impl Debug for ReuseList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ReuseList") + .field("items", &self.items) + .field("slots", &self.slots) + .finish() + } +} + +impl ReuseList { + pub fn new() -> Self { + Self::with_capacity(0) + } + + //is empty + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + //create a with capacity + pub fn with_capacity(capacity: usize) -> Self { + Self { + items: Vec::with_capacity(capacity), + slots: Vec::with_capacity(capacity >> 2), + last_slot_idx: 0, + len: 0, + slot_size: 0, + } + } + + pub fn append(&mut self, item: T) -> usize { + if self.slot_size > 0 { + //reuse empty slot if valid + let slot = self.slots[self.last_slot_idx - 1]; + if slot > 0 { + self.items[slot - 1] = Some(item); + self.slots[self.last_slot_idx - 1] = 0; + if self.last_slot_idx > 1 { + self.last_slot_idx -= 1; + } + + self.len += 1; + return slot - 1; + } + } + //no valid empty slots, append to end + self.items.push(Some(item)); + self.len += 1; + self.items.len() - 1 + } + + pub fn remove(&mut self, index: usize) -> Option { + if index >= self.items.len() { + return None; + } + + let item = self.items[index].take(); + if item.is_some() { + if self.slot_size > 0 && self.slots[self.last_slot_idx - 1] == 0 { + self.slots[self.last_slot_idx - 1] = index + 1; + } else { + self.slots.push(index + 1); + self.last_slot_idx += 1; + self.slot_size += 1; + } + self.len -= 1; + } + item + } + + pub fn get(&self, index: usize) -> Option<&T> { + if index >= self.items.len() { + None + } else { + self.items[index].as_ref() + } + } + + pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { + if index >= self.items.len() { + None + } else { + self.items[index].as_mut() + } + } + + pub fn capacity(&self) -> usize { + self.items.capacity() + } + + pub fn len(&self) -> usize { + self.len + } + + pub fn iter(&self) -> impl Iterator { + self.items.iter().filter_map(|x| x.as_ref()) + } + + pub fn iter_mut(&mut self) -> impl Iterator { + self.items.iter_mut().filter_map(|x| x.as_mut()) + } + + //implement clear + pub fn clear(&mut self) { + self.items.clear(); + self.slots.clear(); + self.last_slot_idx = 0; + self.len = 0; + self.slot_size = 0; + } + + pub fn optimize(&mut self) { + let mut new_items = Vec::with_capacity(self.len); + + for item in self.items.iter_mut() { + let a = item.take(); + if a.is_some() { + new_items.push(a); + } + } + self.items = new_items; + self.slots.clear(); + self.last_slot_idx = 0; + self.slot_size = 0; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_new() { + let list: ReuseList = ReuseList::new(); + assert_eq!(list.len(), 0); + assert_eq!(list.capacity(), 0); + assert_eq!(list.items.len(), 0); + assert_eq!(list.slots.len(), 0); + } + + #[test] + fn test_with_capacity() { + let list: ReuseList = ReuseList::with_capacity(10); + assert_eq!(list.len(), 0); + assert_eq!(list.capacity(), 10); + assert_eq!(list.items.len(), 0); + assert_eq!(list.slots.len(), 0); + } + + #[test] + fn test_append() { + let mut list = ReuseList::new(); + assert_eq!(list.append(1), 0); + assert_eq!(list.append(2), 1); + assert_eq!(list.append(3), 2); + assert_eq!(list.len(), 3); + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![1, 2, 3]); + assert_eq!(list.items, vec![Some(1), Some(2), Some(3)]); + assert_eq!(list.slots, vec![]); + } + + #[test] + fn test_remove() { + let mut list = ReuseList::new(); + list.append(1); + list.append(2); + list.append(3); + + assert_eq!(list.remove(1), Some(2)); + assert_eq!(list.len(), 2); + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![1, 3]); + assert_eq!(list.items, vec![Some(1), None, Some(3)]); + assert_eq!(list.slots, vec![2]); + + assert_eq!(list.remove(5), None); + } + + #[test] + fn test_reuse_slots() { + let mut list = ReuseList::new(); + list.append(1); + list.append(2); + list.append(3); + + list.remove(1); // Remove 2 + assert_eq!(list.append(4), 1); // Should reuse index 1 + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![1, 4, 3]); + assert_eq!(list.items, vec![Some(1), Some(4), Some(3)]); + assert_eq!(list.slots, vec![0]); + } + + #[test] + fn test_get() { + let mut list = ReuseList::new(); + list.append(1); + list.append(2); + + assert_eq!(list.get(0), Some(&1)); + assert_eq!(list.get(1), Some(&2)); + assert_eq!(list.get(2), None); + assert_eq!(list.items, vec![Some(1), Some(2)]); + assert_eq!(list.slots, vec![]); + } + + #[test] + fn test_get_mut() { + let mut list = ReuseList::new(); + list.append(1); + list.append(2); + + if let Some(value) = list.get_mut(0) { + *value = 10; + } + + assert_eq!(list.get(0), Some(&10)); + assert_eq!(list.items, vec![Some(10), Some(2)]); + assert_eq!(list.slots, vec![]); + } + + #[test] + fn test_iter() { + let mut list = ReuseList::new(); + list.append(1); + list.append(2); + list.append(3); + list.remove(1); + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![1, 3]); + assert_eq!(list.items, vec![Some(1), None, Some(3)]); + assert_eq!(list.slots, vec![2]); + } + + #[test] + fn test_iter_mut() { + let mut list = ReuseList::new(); + list.append(1); + list.append(2); + list.append(3); + + for item in list.iter_mut() { + *item *= 2; + } + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![2, 4, 6]); + assert_eq!(list.items, vec![Some(2), Some(4), Some(6)]); + assert_eq!(list.slots, vec![]); + } + + #[test] + fn test_multiple_removes() { + let mut list = ReuseList::new(); + for i in 0..5 { + list.append(i); + } + + list.remove(1); + list.remove(3); + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![0, 2, 4]); + assert_eq!(list.items, vec![Some(0), None, Some(2), None, Some(4)]); + assert_eq!(list.slots, vec![2, 4]); + + // Test reuse of both slots + list.append(10); + list.append(11); + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![0, 11, 2, 10, 4]); + assert_eq!( + list.items, + vec![Some(0), Some(11), Some(2), Some(10), Some(4)] + ); + assert_eq!(list.slots, vec![0, 0]); + + list.remove(0); + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![11, 2, 10, 4]); + assert_eq!(list.items, vec![None, Some(11), Some(2), Some(10), Some(4)]); + assert_eq!(list.slots, vec![1, 0]); + + list.append(20); + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![20, 11, 2, 10, 4]); + assert_eq!( + list.items, + vec![Some(20), Some(11), Some(2), Some(10), Some(4)] + ); + assert_eq!(list.slots, vec![0, 0]); + + //remove all items + list.clear(); + } + + #[test] + fn test_optimize() { + let mut list = ReuseList::new(); + list.append(1); + list.append(2); + list.append(3); + list.remove(1); + + assert_eq!(list.items, vec![Some(1), None, Some(3)]); + assert_eq!(list.slots, vec![2]); + + list.optimize(); + + assert_eq!(list.items, vec![Some(1), Some(3)]); + assert_eq!(list.slots, vec![]); + assert_eq!(list.last_slot_idx, 0); + assert_eq!(list.slot_size, 0); + + let items: Vec = list.iter().cloned().collect(); + assert_eq!(items, vec![1, 3]); + } +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/signals.rs b/host/cred-script/vendor/llrt_utils_watts/src/signals.rs new file mode 100644 index 0000000..dbebd2f --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/signals.rs @@ -0,0 +1,149 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{prelude::Opt, Ctx, Exception, Result, Value}; + +use crate::result::ResultExt; +use std::io; + +#[cfg(unix)] +macro_rules! generate_signal_from_str_fn { + ($($signal:path),*) => { + pub fn signal_from_str(signal: &str) -> Option { + let signal = ["libc::", signal].concat(); + match signal.as_str() { + $(stringify!($signal) => Some($signal),)* + _ => None, + } + } + + pub fn signal_str_from_i32(signal: i32) -> Option<&'static str> { + $(if signal == $signal { + return Some(&stringify!($signal)[6..]); + })* + None + } + }; +} + +#[cfg(unix)] +generate_signal_from_str_fn!( + libc::SIGHUP, + libc::SIGINT, + libc::SIGQUIT, + libc::SIGILL, + libc::SIGABRT, + libc::SIGFPE, + libc::SIGKILL, + libc::SIGSEGV, + libc::SIGPIPE, + libc::SIGALRM, + libc::SIGTERM +); + +#[cfg(not(unix))] +static WINDOWS_SIGTERM: i32 = -1; + +pub fn parse_signal(signal: Option>) -> Result { + let Some(val) = signal else { + #[cfg(unix)] + return Ok(libc::SIGTERM); + #[cfg(not(unix))] + return Ok(WINDOWS_SIGTERM); + }; + + if let Some(num) = val.as_number() { + let sig = num as i32; + #[cfg(unix)] + return Ok(sig); + // On Windows: 0 checks existence, anything else kills + #[cfg(not(unix))] + return Ok(if sig == 0 { 0 } else { WINDOWS_SIGTERM }); + } + + if let Some(str_val) = val.as_string() { + let s = str_val.to_string()?; + + #[cfg(unix)] + let mapped_sig = signal_from_str(&s); + + #[cfg(not(unix))] + let mapped_sig = match s.as_str() { + "SIGINT" | "SIGTERM" | "SIGKILL" | "SIGQUIT" | "SIGHUP" | "SIGUSR1" => { + Some(WINDOWS_SIGTERM) + }, + _ => None, + }; + + return match mapped_sig { + Some(sig) => Ok(sig), + None => Err(Exception::throw_type( + val.ctx(), + &format!("Unknown signal: {}", s), + )), + }; + } + + Err(Exception::throw_type(val.ctx(), "Invalid signal type")) +} + +#[cfg(unix)] +pub fn kill_process_raw(pid: u32, signal: i32) -> io::Result<()> { + // libc::kill returns 0 on success, -1 on error + // SAFETY: kill is a safe system call as long as the signal value is valid, which is ensured by parse_signal + if unsafe { libc::kill(pid as i32, signal) } == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } +} + +#[cfg(windows)] +pub fn kill_process_raw(pid: u32, signal: i32) -> io::Result<()> { + use windows_sys::Win32::Foundation::CloseHandle; + use windows_sys::Win32::System::Threading::{OpenProcess, TerminateProcess, PROCESS_TERMINATE}; + + // SAFETY: OpenProcess is safe to call with valid parameters, and PROCESS_TERMINATE is a valid access right + let handle = unsafe { OpenProcess(PROCESS_TERMINATE, 0, pid) }; + if handle == std::ptr::null_mut() { + return Err(io::Error::last_os_error()); + } + + let result = if signal == 0 { + Ok(()) + } else { + // SAFETY: TerminateProcess is safe to call with a valid process handle obtained from OpenProcess + if unsafe { TerminateProcess(handle, 1) } != 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + }; + + // SAFETY: CloseHandle is safe to call with a valid handle obtained from OpenProcess + unsafe { CloseHandle(handle) }; + result +} + +pub fn kill(ctx: &Ctx<'_>, pid: u32, signal: Opt>) -> Result { + let signal = parse_signal(signal.0)?; + + kill_process_raw(pid, signal) + .map(|_| true) + .or_else(|e| { + // Handle "Process Not Found" / "Existence Check" logic + // If signal is 0 (check existence) and we hit a specific error, return Ok(false). + + #[cfg(unix)] + let is_not_found = e.raw_os_error() == Some(libc::ESRCH); // Error 3 + + #[cfg(windows)] + let is_not_found = true; // On Windows, any OpenProcess failure during check implies "not found" (or not accessible) + + if signal == 0 && is_not_found { + Ok(false) + } else { + Err(e) + } + }) + .or_throw(ctx) +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/string.rs b/host/cred-script/vendor/llrt_utils_watts/src/string.rs new file mode 100644 index 0000000..20194f7 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/string.rs @@ -0,0 +1,17 @@ +use rquickjs::{Coerced, Result, Value}; + +#[inline] +pub fn get_string(value: &Value<'_>) -> Result> { + if let Some(val) = value.as_string() { + let string = val.to_string()?; + return Ok(Some(string)); + } + Ok(None) +} + +pub fn get_coerced_string(value: &Value<'_>) -> Option { + if let Ok(val) = value.get::>() { + return Some(val.0); + }; + None +} diff --git a/host/cred-script/vendor/llrt_utils_watts/src/sysinfo.rs b/host/cred-script/vendor/llrt_utils_watts/src/sysinfo.rs new file mode 100644 index 0000000..f584484 --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/sysinfo.rs @@ -0,0 +1,13 @@ +#[cfg(target_os = "macos")] +pub const PLATFORM: &str = "darwin"; +#[cfg(target_os = "windows")] +pub const PLATFORM: &str = "win32"; +#[cfg(not(any(target_os = "macos", target_os = "windows")))] +pub const PLATFORM: &str = std::env::consts::OS; + +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +pub const ARCH: &str = "x64"; +#[cfg(target_arch = "aarch64")] +pub const ARCH: &str = "arm64"; +#[cfg(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64")))] +pub const ARCH: &str = std::env::consts::ARCH; diff --git a/host/cred-script/vendor/llrt_utils_watts/src/time.rs b/host/cred-script/vendor/llrt_utils_watts/src/time.rs new file mode 100644 index 0000000..abb9a7d --- /dev/null +++ b/host/cred-script/vendor/llrt_utils_watts/src/time.rs @@ -0,0 +1,47 @@ +use std::{ + sync::atomic::{AtomicU64, Ordering}, + time::SystemTime, +}; + +static TIME_ORIGIN: AtomicU64 = AtomicU64::new(0); + +/// Get the current time in nanoseconds. +/// +/// # Safety +/// - Good until the year 2554 +/// - Always use a checked substraction since this can return 0 +pub fn now_nanos() -> u64 { + SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_nanos() as u64 +} + +/// Get the current time in millis. +/// +/// # Safety +/// - Good until the year 2554 +/// - Always use a checked substraction since this can return 0 +pub fn now_millis() -> i64 { + SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_millis() as i64 +} + +/// Get the origin time in nanoseconds. +/// +/// # Safety +/// - Good until the year 2554 +/// - Always use a checked substraction since this can return 0 +pub fn origin_nanos() -> u64 { + TIME_ORIGIN.load(Ordering::Relaxed) +} + +// For accuracy reasons, this function should be executed when the vm is initialized +pub fn init() { + if TIME_ORIGIN.load(Ordering::Relaxed) == 0 { + let time_origin = now_nanos(); + TIME_ORIGIN.store(time_origin, Ordering::Relaxed) + } +} diff --git a/host/cred-script/vendor/rquickjs-sys/.cargo_vcs_info.json b/host/cred-script/vendor/rquickjs-sys/.cargo_vcs_info.json new file mode 100644 index 0000000..74f3ecd --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "c99675e50201d74554d0f667094f800e1287001b" + }, + "path_in_vcs": "sys" +} \ No newline at end of file diff --git a/host/cred-script/vendor/rquickjs-sys/.gitignore b/host/cred-script/vendor/rquickjs-sys/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/.gitignore @@ -0,0 +1 @@ +target diff --git a/host/cred-script/vendor/rquickjs-sys/Cargo.lock b/host/cred-script/vendor/rquickjs-sys/Cargo.lock new file mode 100644 index 0000000..296c697 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/Cargo.lock @@ -0,0 +1,319 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "cc" +version = "1.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f50d563227a1c37cc0a263f64eca3334388c01c5e4c4861a9def205c614383c" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.178" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rquickjs-sys" +version = "0.11.0" +dependencies = [ + "bindgen", + "cc", + "pretty_env_logger", +] + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/host/cred-script/vendor/rquickjs-sys/Cargo.toml b/host/cred-script/vendor/rquickjs-sys/Cargo.toml new file mode 100644 index 0000000..5019dfd --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/Cargo.toml @@ -0,0 +1,68 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "rquickjs-sys" +version = "0.11.0" +authors = ["Mees Delzenne "] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "QuickJS bindings for rquickjs" +readme = "README.md" +keywords = [ + "quickjs", + "ecmascript", + "javascript", + "es6", + "es2020", +] +categories = ["external-ffi-bindings"] +license = "MIT" +repository = "https://github.com/DelSkayn/rquickjs.git" + +[features] +bindgen = ["bindgen-rs"] +disable-assertions = [] +dump-atoms = [] +dump-bytecode = [] +dump-free = [] +dump-gc = [] +dump-gc-free = [] +dump-leaks = [] +dump-mem = [] +dump-module-resolve = [] +dump-objects = [] +dump-promise = [] +dump-read-object = [] +dump-shapes = [] +logging = ["pretty_env_logger"] +update-bindings = ["bindgen"] + +[lib] +name = "rquickjs_sys" +path = "src/lib.rs" + +[build-dependencies.bindgen-rs] +version = "0.72" +optional = true +package = "bindgen" + +[build-dependencies.cc] +version = "1" + +[build-dependencies.pretty_env_logger] +version = "0.5" +optional = true diff --git a/host/cred-script/vendor/rquickjs-sys/Cargo.toml.orig b/host/cred-script/vendor/rquickjs-sys/Cargo.toml.orig new file mode 100644 index 0000000..1b992fa --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/Cargo.toml.orig @@ -0,0 +1,48 @@ +[package] +name = "rquickjs-sys" +version = "0.11.0" +authors = ["Mees Delzenne "] +edition = "2021" +license = "MIT" +readme = "README.md" +description = "QuickJS bindings for rquickjs" +keywords = ["quickjs", "ecmascript", "javascript", "es6", "es2020"] +categories = ["external-ffi-bindings"] +repository = "https://github.com/DelSkayn/rquickjs.git" + +[build-dependencies] +cc = "1" + +[build-dependencies.bindgen-rs] +package = "bindgen" +version = "0.72" +optional = true + +[build-dependencies.pretty_env_logger] +version = "0.5" +optional = true + +[features] +bindgen = ["bindgen-rs"] + +# Debug logging +logging = ["pretty_env_logger"] +# Special case for updating bundled bindings +update-bindings = ["bindgen"] + +# Enable QuickJS dumps +dump-bytecode = [] +dump-gc = [] +dump-gc-free = [] +dump-free = [] +dump-leaks = [] +dump-mem = [] +dump-objects = [] +dump-atoms = [] +dump-shapes = [] +dump-module-resolve = [] +dump-promise = [] +dump-read-object = [] + +# Disable QuickJS assertions for better performance +disable-assertions = [] diff --git a/host/cred-script/vendor/rquickjs-sys/Makefile b/host/cred-script/vendor/rquickjs-sys/Makefile new file mode 100644 index 0000000..21b9b8b --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/Makefile @@ -0,0 +1,28 @@ +patch = all #hotfix msvc exports + +$(info patch = $(patch)) + +ifneq ($(filter hotfix all,$(patch)),) +PATCHES += get_function_proto +PATCHES += check_stack_overflow +endif + +# apply patches +apply: + @cd quickjs $(foreach PATCH,$(PATCHES), && echo '*** $(PATCH) ***' && patch -p1 < ../patches/$(PATCH).patch) + +# stage changes +stage: + @cd quickjs && git add * + +# show unstaged diff +diff: + @cd quickjs && git diff -w + +# update patch from unstaged changes +update.%: + @cd quickjs && git diff -w > ../patches/$*.patch + +# reset patches +reset: + @cd quickjs && git reset --hard HEAD diff --git a/host/cred-script/vendor/rquickjs-sys/README.md b/host/cred-script/vendor/rquickjs-sys/README.md new file mode 100644 index 0000000..b072f19 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/README.md @@ -0,0 +1,24 @@ +# rquickjs-sys + +[![github](https://img.shields.io/badge/github-delskayn/rquickjs-8da0cb.svg?style=for-the-badge&logo=github)](https://github.com/DelSkayn/rquickjs) +[![crates](https://img.shields.io/crates/v/rquickjs.svg?style=for-the-badge&color=fc8d62&logo=rust)](https://crates.io/crates/rquickjs-sys) +[![docs](https://img.shields.io/badge/docs.rs-rquickjs-66c2a5?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K)](https://docs.rs/rquickjs-sys) +[![status](https://img.shields.io/github/actions/workflow/status/DelSkayn/rquickjs/ci.yml?branch=master&style=for-the-badge&logo=github-actions&logoColor=white)](https://github.com/DelSkayn/rquickjs/actions?query=workflow%3ARust) + +This crate is a low level unsafe raw bindings for the [QuickJS](https://bellard.org/quickjs/) JavaScript engine. + +__NOTE:__ Usually you shouldn't use this crate directly, instead use [rquickjs](https://crates.io/crates/rquickjs) crate which provides high level safe bindings. + +## Patches + +In order to fix bugs and get support for some unimplemented features the series of patches applies to released sources. + +Hot fixes: +- Fix for _check stack overflow_ (important for Rust) +- Atomic support for `JS_NewClassID` (important for Rust) +- Infinity handling (replacement `1.0 / 0.0` to `INFINITY` constant) + +Special patches: +- Reading module exports (`exports` feature) +- Reset stack function (`parallel` feature) +- MSVC support diff --git a/host/cred-script/vendor/rquickjs-sys/build.rs b/host/cred-script/vendor/rquickjs-sys/build.rs new file mode 100644 index 0000000..299ff94 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/build.rs @@ -0,0 +1,372 @@ +#![allow(clippy::uninlined_format_args)] +use std::{ + env, fs, + path::{Path, PathBuf}, + process::{self}, +}; + +// WASI logic lifted from https://github.com/bytecodealliance/javy/blob/61616e1507d2bf896f46dc8d72687273438b58b2/crates/quickjs-wasm-sys/build.rs#L18 + +const WASI_SDK_VERSION_MAJOR: usize = 24; +const WASI_SDK_VERSION_MINOR: usize = 0; + +fn download_wasi_sdk() -> PathBuf { + let mut wasi_sdk_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); + wasi_sdk_dir.push("wasi-sdk"); + + fs::create_dir_all(&wasi_sdk_dir).unwrap(); + + let major_version = WASI_SDK_VERSION_MAJOR; + let minor_version = WASI_SDK_VERSION_MINOR; + + let mut archive_path = wasi_sdk_dir.clone(); + archive_path.push(format!("wasi-sdk-{major_version}-{minor_version}.tar.gz")); + + println!("SDK tar: {archive_path:?}"); + + // Download archive if necessary + if !archive_path.try_exists().unwrap() { + let file_suffix = match (env::consts::OS, env::consts::ARCH) { + ("linux", "x86") | ("linux", "x86_64") => "x86_64-linux", + ("linux", "aarch64") => "arm64-linux", + ("macos", "x86") | ("macos", "x86_64") => "x86_64-macos", + ("macos", "aarch64") => "arm64-macos", + ("windows", "x86") | ("windows", "x86_64") => "x86_64-windows", + ("windows", "aarch64") => "arm64-windows", + other => panic!("Unsupported platform tuple {:?}", other), + }; + + let uri = format!("https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-{major_version}/wasi-sdk-{major_version}.{minor_version}-{file_suffix}.tar.gz"); + + println!("Downloading WASI SDK archive from {uri} to {archive_path:?}"); + + let output = process::Command::new("curl") + .args([ + "--location", + "-o", + archive_path.to_string_lossy().as_ref(), + uri.as_ref(), + ]) + .output() + .expect("failed to download the WASI SDK with curl"); + println!("curl output: {}", String::from_utf8_lossy(&output.stdout)); + println!("curl err: {}", String::from_utf8_lossy(&output.stderr)); + if !output.status.success() { + panic!( + "curl WASI SDK failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + } + + let mut test_binary = wasi_sdk_dir.clone(); + test_binary.extend(["bin", "wasm-ld"]); + // Extract archive if necessary + if !test_binary.try_exists().unwrap() { + println!("Extracting WASI SDK archive {archive_path:?}"); + let output = process::Command::new("tar") + .args([ + "-zxf", + archive_path.to_string_lossy().as_ref(), + "--strip-components", + "1", + ]) + .current_dir(&wasi_sdk_dir) + .output() + .unwrap(); + if !output.status.success() { + panic!( + "Unpacking WASI SDK failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + } + + wasi_sdk_dir +} + +fn get_wasi_sdk_path() -> PathBuf { + std::env::var_os("WASI_SDK") + .map(PathBuf::from) + .unwrap_or_else(download_wasi_sdk) +} + +fn main() { + #[cfg(feature = "logging")] + pretty_env_logger::init(); + + let features = [ + "bindgen", + "update-bindings", + "dump-bytecode", + "dump-gc", + "dump-gc-free", + "dump-free", + "dump-leaks", + "dump-mem", + "dump-objects", + "dump-atoms", + "dump-shapes", + "dump-module-resolve", + "dump-promise", + "dump-read-object", + "disable-assertions", + ]; + + for feature in &features { + println!("cargo:rerun-if-env-changed={}", feature_to_cargo(feature)); + } + println!("cargo:rerun-if-env-changed=CARGO_CFG_SANITIZE"); + println!("cargo:rerun-if-changed=quickjs"); + + let src_dir = Path::new("quickjs"); + + let out_dir = env::var("OUT_DIR").expect("No OUT_DIR env var is set by cargo"); + let out_dir = Path::new(&out_dir); + + let header_files = [ + "builtin-array-fromasync.h", + "dtoa.h", + "libregexp-opcode.h", + "libregexp.h", + "libunicode-table.h", + "libunicode.h", + "list.h", + "quickjs-atom.h", + "quickjs-opcode.h", + "quickjs-c-atomics.h", + "quickjs.h", + "cutils.h", + ]; + + let source_files = [ + "libregexp.c", + "libunicode.c", + "cutils.c", + "quickjs.c", + "dtoa.c", + ]; + + let mut defines: Vec<(String, Option<&str>)> = vec![("_GNU_SOURCE".into(), None)]; + + #[cfg(feature = "disable-assertions")] + defines.push(("NDEBUG".into(), None)); + + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); + + let mut builder = cc::Build::new(); + builder + .extra_warnings(false) + .flag_if_supported("-Wno-implicit-const-int-float-conversion") + //.flag("-Wno-array-bounds") + //.flag("-Wno-format-truncation") + ; + + match env::var("CARGO_CFG_SANITIZE").as_deref() { + Ok("address") => { + builder + .flag("-fsanitize=address") + .flag("-fno-sanitize-recover=all") + .flag("-fno-omit-frame-pointer"); + } + Ok("memory") => { + builder + .flag("-fsanitize=memory") + .flag("-fno-sanitize-recover=all") + .flag("-fno-omit-frame-pointer"); + } + Ok("thread") => { + builder + .flag("-fsanitize=thread") + .flag("-fno-sanitize-recover=all") + .flag("-fno-omit-frame-pointer"); + } + Ok(x) => println!("cargo:warning=Unsupported sanitize_option: '{x}'"), + _ => {} + } + + let mut bindgen_cflags = vec![]; + + if target_os == "windows" { + if target_env == "msvc" { + env::set_var( + "CFLAGS", + "/DWIN32_LEAN_AND_MEAN /std:c11 /experimental:c11atomics", + ); + } else { + env::set_var("CFLAGS", "-DWIN32_LEAN_AND_MEAN -std=c11"); + } + } + + if target_os == "wasi" { + // pretend we're emscripten - there are already ifdefs that match + // also, wasi doesn't ahve FE_DOWNWARD or FE_UPWARD + defines.push(("EMSCRIPTEN".into(), Some("1"))); + defines.push(("FE_DOWNWARD".into(), Some("0"))); + defines.push(("FE_UPWARD".into(), Some("0"))); + } + + for file in source_files.iter().chain(header_files.iter()) { + fs::copy(src_dir.join(file), out_dir.join(file)) + .expect("Unable to copy source; try 'git submodule update --init'"); + } + fs::copy("quickjs.bind.h", out_dir.join("quickjs.bind.h")).expect("Unable to copy source"); + + // SAU-103: use cargo.build's target-specific WASI compiler/archive tools. + if target_os == "wasi" && env::var_os("CC_wasm32_wasip2").is_none() { + let wasi_sdk_path = get_wasi_sdk_path(); + if !wasi_sdk_path.try_exists().unwrap() { + panic!( + "wasi-sdk not installed in specified path of {}", + wasi_sdk_path.display() + ); + } + env::set_var("CC", wasi_sdk_path.join("bin/clang").to_str().unwrap()); + env::set_var("AR", wasi_sdk_path.join("bin/ar").to_str().unwrap()); + let sysroot = format!( + "--sysroot={}", + wasi_sdk_path.join("share/wasi-sysroot").display() + ); + env::set_var("CFLAGS", &sysroot); + bindgen_cflags.push(sysroot); + } + + // generating bindings + bindgen( + out_dir, + out_dir.join("quickjs.bind.h"), + &defines, + bindgen_cflags, + ); + + for (name, value) in &defines { + builder.define(name, *value); + } + + for src in &source_files { + builder.file(out_dir.join(src)); + } + + let tool = builder.get_compiler(); + println!("cargo:warning=SAU-103 QuickJS C compiler {:?} args {:?}", tool.path(), tool.args()); + builder.compile("libquickjs.a"); +} + +fn feature_to_cargo(name: impl AsRef) -> String { + format!("CARGO_FEATURE_{}", feature_to_define(name)) +} + +fn feature_to_define(name: impl AsRef) -> String { + name.as_ref().to_uppercase().replace('-', "_") +} + +#[cfg(not(feature = "bindgen"))] +fn bindgen<'a, D, H, X, K, V>(out_dir: D, _header_file: H, _defines: X, _add_cflags: Vec) +where + D: AsRef, + H: AsRef, + X: IntoIterator)>, + K: AsRef + 'a, + V: AsRef + 'a, +{ + let target = env::var("TARGET").unwrap(); + + if !Path::new("./") + .join("src") + .join("bindings") + .join(format!("{}.rs", target)) + .canonicalize() + .map(|x| x.exists()) + .unwrap_or(false) + { + println!( + "cargo:warning=rquickjs probably doesn't ship bindings for platform `{}({})`. try the `bindgen` feature instead.", + target, + env::var("BUILD_TARGET").unwrap_or("n/a".into()) + ); + } + + let bindings_file = out_dir.as_ref().join("bindings.rs"); + + fs::write( + bindings_file, + format!( + r#"macro_rules! bindings_env {{ + ("TARGET") => {{ "{target}" }}; + }}"# + ), + ) + .unwrap(); +} + +#[cfg(feature = "bindgen")] +fn bindgen<'a, D, H, X, K, V>(out_dir: D, header_file: H, defines: X, mut add_cflags: Vec) +where + D: AsRef, + H: AsRef, + X: IntoIterator)>, + K: AsRef + 'a, + V: AsRef + 'a, +{ + let mut target = env::var("TARGET").unwrap(); + let out_dir = out_dir.as_ref(); + let header_file = header_file.as_ref(); + + // *-pc-windows-gnullvm is special for Rust, Clang accepts only + // *-pc-windows-gnu + if target.ends_with("windows-gnullvm") { + target = target.replace("llvm", ""); + } + + let mut cflags = vec![format!("--target={}", target)]; + cflags.append(&mut add_cflags); + + //format!("-I{}", out_dir.parent().display()), + + for (name, value) in defines { + cflags.push(if let Some(value) = value { + format!("-D{}={}", name.as_ref(), value.as_ref()) + } else { + format!("-D{}", name.as_ref()) + }); + } + + let mut builder = bindgen_rs::Builder::default() + .use_core() + .detect_include_paths(true) + .clang_arg("-xc") + .clang_arg("-v") + .clang_args(cflags) + .size_t_is_usize(false) + .header(header_file.display().to_string()) + .allowlist_type("JS.*") + .allowlist_function("js.*") + .allowlist_function("JS.*") + .allowlist_function("__JS.*") + .allowlist_var("JS.*") + .opaque_type("FILE") + .blocklist_type("FILE") + .blocklist_function("JS_DumpMemoryUsage"); + + if env::var("CARGO_CFG_TARGET_OS").unwrap() == "wasi" { + builder = builder.clang_arg("-fvisibility=default"); + } + + let bindings = builder.generate().expect("Unable to generate bindings"); + + let bindings_file = out_dir.join("bindings.rs"); + + bindings + .write_to_file(&bindings_file) + .expect("Couldn't write bindings"); + + // Special case to support bundled bindings + if env::var("CARGO_FEATURE_UPDATE_BINDINGS").is_ok() { + let dest_dir = Path::new("src").join("bindings"); + fs::create_dir_all(&dest_dir).unwrap(); + + let dest_file = format!("{}.rs", target); + fs::copy(&bindings_file, dest_dir.join(dest_file)).unwrap(); + } +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs.bind.h b/host/cred-script/vendor/rquickjs-sys/quickjs.bind.h new file mode 100644 index 0000000..a4784da --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs.bind.h @@ -0,0 +1,16 @@ +// A header which imports the all symbols of the quickjs header but also exports +// the static atoms. + +#include "quickjs.h" + +#if !defined(EMSCRIPTEN) && !defined(_MSC_VER) +#define CONFIG_ATOMICS +#endif + +enum { + __JS_ATOM_NULL = JS_ATOM_NULL, +#define DEF(name, str) JS_ATOM_##name, +#include "quickjs-atom.h" +#undef DEF + JS_ATOM_END, +}; diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.gitattributes b/host/cred-script/vendor/rquickjs-sys/quickjs/.gitattributes new file mode 100644 index 0000000..2473e87 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.gitattributes @@ -0,0 +1,4 @@ +# Don't show changes in generated files when doing git diff + +gen/** -diff + diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.github/dependabot.yml b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/dependabot.yml new file mode 100644 index 0000000..700707c --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/ci.yml b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/ci.yml new file mode 100644 index 0000000..df30140 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/ci.yml @@ -0,0 +1,780 @@ +name: ci + +on: + pull_request: + paths: + - '**' + - '!.gitignore' + - '!LICENSE' + - '!README.md' + - '!docs/**' + - '!examples/**' + - '.github/workflows/ci.yml' + push: + branches: + - master + paths: + - '**' + - '!.gitignore' + - '!LICENSE' + - '!README.md' + - '!docs/**' + - '!examples/**' + - '.github/workflows/ci.yml' + +jobs: + codegen: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: build + run: | + make codegen + - name: Check if the git repository is clean + run: (exit "$(git status --porcelain --untracked-files=no | head -255 | wc -l)") || (echo "Dirty git tree"; git diff; exit 1) + + ci: + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.os }} (${{ matrix.config.configType }}${{ matrix.config.arch }}) + env: + ASAN_OPTIONS: halt_on_error=1 + MSAN_OPTIONS: halt_on_error=1 + UBSAN_OPTIONS: halt_on_error=1 + defaults: + run: + shell: ${{ matrix.config.arch == '' && 'sh' || 'alpine.sh' }} {0} + + strategy: + fail-fast: false + matrix: + config: + # see https://github.com/quickjs-ng/quickjs/issues/879 - tl;dr flaky + #- { os: ubuntu-24.04-arm, configType: Debug } + #- { os: ubuntu-24.04-arm, configType: Release, runTest262: true } + - { os: ubuntu-latest, configType: Debug } + - { os: ubuntu-latest, configType: Release, runTest262: true } + - { os: ubuntu-latest, configType: examples } + - { os: ubuntu-latest, configType: shared } + - { os: ubuntu-latest, configType: asan+ubsan, runTest262: true } + - { os: ubuntu-latest, configType: msan } + - { os: ubuntu-latest, configType: tcc } + - { os: ubuntu-latest, arch: x86, runTest262: true } + - { os: ubuntu-latest, arch: riscv64 } + - { os: ubuntu-latest, arch: s390x } + + - { os: macos-14, configType: Debug } + - { os: macos-14, configType: Release } + - { os: macos-14, configType: examples } + - { os: macos-14, configType: shared } + - { os: macos-14, configType: asan+ubsan } + steps: + - uses: actions/checkout@v6 + with: + submodules: true + + - name: install TCC + if: ${{ matrix.config.configType == 'tcc' }} + run: | + pushd /tmp + git clone https://repo.or.cz/tinycc.git + cd tinycc + git checkout c21576f8a32715ab439690d18184b0e02022bbbd + ./configure + make + sudo make install + tcc -v + popd + echo "CC=tcc" >> $GITHUB_ENV; + + - name: Install extra dependencies + if: ${{ matrix.config.arch != '' }} + shell: 'sh' + run: | + sudo apt update && sudo apt install -y binfmt-support + + - name: Setup Alpine + if: ${{ matrix.config.arch != '' }} + uses: jirutka/setup-alpine@v1 + with: + arch: ${{ matrix.config.arch }} + packages: "build-base make cmake git" + + - name: uname + run: uname -a + + - name: Set build ENV vars + run: | + if [ "${{ matrix.config.configType }}" = "Debug" ]; then + echo "BUILD_TYPE=Debug" >> $GITHUB_ENV; + elif [ "${{ matrix.config.configType }}" = "examples" ]; then + echo "QJS_BUILD_EXAMPLES=ON" >> $GITHUB_ENV; + elif [ "${{ matrix.config.configType }}" = "shared" ]; then + echo "BUILD_SHARED_LIBS=ON" >> $GITHUB_ENV; + elif [ "${{ matrix.config.configType }}" = "asan+ubsan" ]; then + echo "BUILD_TYPE=RelWithDebInfo" >> $GITHUB_ENV; + echo "QJS_ENABLE_ASAN=ON" >> $GITHUB_ENV; + echo "QJS_ENABLE_UBSAN=ON" >> $GITHUB_ENV; + elif [ "${{ matrix.config.configType }}" = "msan" ]; then + echo "BUILD_TYPE=RelWithDebInfo" >> $GITHUB_ENV; + echo "QJS_ENABLE_MSAN=ON" >> $GITHUB_ENV; + echo "CC=clang" >> $GITHUB_ENV; + fi + + - name: build + run: | + make \ + BUILD_TYPE=$BUILD_TYPE \ + QJS_BUILD_EXAMPLES=$QJS_BUILD_EXAMPLES \ + BUILD_SHARED_LIBS=$BUILD_SHARED_LIBS \ + QJS_ENABLE_ASAN=$QJS_ENABLE_ASAN \ + QJS_ENABLE_UBSAN=$QJS_ENABLE_UBSAN \ + QJS_ENABLE_MSAN=$QJS_ENABLE_MSAN + + - name: stats + if: ${{ matrix.config.configType != 'examples' }} + run: | + make stats + + - name: cxxtest + run: | + make cxxtest + + - name: test + if: ${{ matrix.config.configType != 'examples' }} + run: | + make test + + - name: test examples + if: ${{ matrix.config.configType == 'examples' }} + run: | + cp build/fib.so examples/ + cp build/point.so examples/ + ./build/qjs examples/test_fib.js + ./build/qjs examples/test_point.js + ./build/qjs tests/test_bjson.js + ./build/function_source + + - name: test 262 + if: ${{ matrix.config.runTest262 }} + run: | + git submodule update --init --checkout --depth 1 + make test262 + + - name: test standalone + run: | + ./build/qjs -c examples/hello.js -o hello + ./hello + + - name: test api + run: | + ./build/api-test + + windows-msvc: + runs-on: ${{ matrix.config.os }} + strategy: + fail-fast: false + matrix: + config: + - { arch: x64, vsArch: x64, buildType: Debug, os: windows-latest } + - { arch: x64, vsArch: x64, buildType: Release, os: windows-latest } + - { arch: Win32, vsArch: x86, buildType: Debug, os: windows-latest } + - { arch: Win32, vsArch: x86, buildType: Release, os: windows-latest } + - { arch: ARM64, vsArch: arm64, buildType: Debug, os: windows-11-arm } + - { arch: ARM64, vsArch: arm64, buildType: Release, os: windows-11-arm } + steps: + - uses: actions/checkout@v6 + - name: build + run: | + cmake -B build -DQJS_BUILD_EXAMPLES=ON -G "Visual Studio 17 2022" -A ${{matrix.config.arch}} + cmake --build build --config ${{matrix.config.buildType}} + - name: stats + run: | + build\${{matrix.config.buildType}}\qjs.exe -qd + - name: test + run: | + cp build\${{matrix.config.buildType}}\fib.dll examples\ + cp build\${{matrix.config.buildType}}\point.dll examples\ + build\${{matrix.config.buildType}}\qjs.exe examples\test_fib.js + build\${{matrix.config.buildType}}\qjs.exe examples\test_point.js + build\${{matrix.config.buildType}}\run-test262.exe -c tests.conf + build\${{matrix.config.buildType}}\function_source.exe + - name: test standalone + run: | + build\${{matrix.config.buildType}}\qjs.exe -c examples\hello.js -o hello.exe + .\hello.exe + - name: test api + run: | + build\${{matrix.config.buildType}}\api-test.exe + - name: Set up Visual Studio shell + uses: egor-tensin/vs-shell@v2 + with: + arch: ${{ matrix.config.vsArch }} + - name: cxxtest + run: | + cl.exe /DJS_NAN_BOXING=0 /Zs cxxtest.cc + cl.exe /DJS_NAN_BOXING=1 /Zs cxxtest.cc + + windows-clang: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + buildType: [Debug, Release] + steps: + - uses: actions/checkout@v6 + - name: build + run: | + git submodule update --init --checkout --depth 1 + cmake -B build -DQJS_BUILD_EXAMPLES=ON -G "Visual Studio 17 2022" -T ClangCL + cmake --build build --config ${{matrix.buildType}} + - name: stats + run: | + build\${{matrix.buildType}}\qjs.exe -qd + - name: cxxtest + run: | + clang-cl.exe /DJS_NAN_BOXING=0 /Zs cxxtest.cc + clang-cl.exe /DJS_NAN_BOXING=1 /Zs cxxtest.cc + - name: test + run: | + cp build\${{matrix.buildType}}\fib.dll examples\ + cp build\${{matrix.buildType}}\point.dll examples\ + build\${{matrix.buildType}}\qjs.exe examples\test_fib.js + build\${{matrix.buildType}}\qjs.exe examples\test_point.js + build\${{matrix.buildType}}\run-test262.exe -c tests.conf + build\${{matrix.buildType}}\function_source.exe + - name: test api + run: | + build\${{matrix.buildType}}\api-test.exe + + windows-ninja: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + buildType: [Debug, Release] + steps: + - uses: actions/checkout@v6 + - name: install ninja + run: | + choco install ninja + ninja.exe --version + - name: build + run: | + git submodule update --init --checkout --depth 1 + cmake -B build -DQJS_BUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=${{matrix.buildType}} -G "Ninja" + cmake --build build + - name: stats + run: | + build\qjs.exe -qd + - name: test + run: | + cp build\fib.dll examples\ + cp build\point.dll examples\ + build\qjs.exe examples\test_fib.js + build\qjs.exe examples\test_point.js + build\run-test262.exe -c tests.conf + build\function_source.exe + - name: test api + run: | + build\api-test.exe + + windows-sdk: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + arch: [x64, Win32] + buildType: [Debug, Release] + steps: + - uses: actions/checkout@v6 + - name: Install windows sdk + uses: ChristopheLav/windows-sdk-install@v1 + with: + version-sdk: 26100 + features: 'OptionId.DesktopCPPx86,OptionId.DesktopCPPx64' + - name: build + run: | + cmake -B build -DQJS_BUILD_EXAMPLES=ON -DCMAKE_SYSTEM_VERSION="10.0.26100.0" -A ${{matrix.arch}} + cmake --build build --config ${{matrix.buildType}} + - name: stats + run: | + build\${{matrix.buildType}}\qjs.exe -qd + - name: test + run: | + cp build\${{matrix.buildType}}\fib.dll examples\ + cp build\${{matrix.buildType}}\point.dll examples\ + build\${{matrix.buildType}}\qjs.exe examples\test_fib.js + build\${{matrix.buildType}}\qjs.exe examples\test_point.js + build\${{matrix.buildType}}\run-test262.exe -c tests.conf + build\${{matrix.buildType}}\function_source.exe + - name: test api + run: | + build\${{matrix.buildType}}\api-test.exe + + windows-mingw: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + buildType: [Debug, Release] + sys: + - mingw32 + - mingw64 + - clang64 + - ucrt64 + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/checkout@v6 + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + update: true + msystem: ${{matrix.sys}} + install: >- + git + make + pacboy: >- + cmake:p + ninja:p + toolchain:p + - name: build + run: | + make BUILD_TYPE=${{matrix.buildType}} + - name: stats + run: | + make stats + ldd build/qjs + - name: cxxtest + if: ${{ matrix.sys != 'clang64' }} + run: | + make cxxtest + - name: cxxtest + if: ${{ matrix.sys == 'clang64' }} + run: | + make cxxtest CXX=clang++ + - name: test + run: | + make test + - name: test standalone + run: | + ./build/qjs -c examples/hello.js -o hello.exe + ./hello + - name: test api + run: | + ./build/api-test + windows-mingw-shared: + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/checkout@v6 + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + install: >- + git + make + pacboy: >- + cmake:p + ninja:p + toolchain:p + - name: build + run: | + make BUILD_SHARED_LIBS=ON + ldd build/qjs + - name: stats + run: | + make stats + + emscripten: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: mymindstorm/setup-emsdk@v14 + - name: check emsdk + run: emcc -v + - name: build + run: | + emcmake cmake -B build -DQJS_BUILD_LIBC=ON + emmake make -C build qjs_wasm "-j$(getconf _NPROCESSORS_ONLN)" + - name: result + run: ls -lh build + wasi: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v6 + - uses: jcbhmr/setup-wasmtime@v2 + - name: setup wasi-sdk + run: | + wget -nv https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.deb -P /tmp + sudo apt install /tmp/wasi-sdk*.deb + - name: test + run: | + cmake -B build -DCMAKE_TOOLCHAIN_FILE=/opt/wasi-sdk/share/cmake/wasi-sdk.cmake + make -C build qjs_exe + wasmtime run build/qjs -qd + echo "console.log('hello wasi!');" > t.js + wasmtime run --dir . build/qjs t.js + + cygwin: + runs-on: windows-latest + defaults: + run: + shell: C:\cygwin\bin\bash.exe --login --norc -eo pipefail -o igncr '{0}' + env: + CYGWIN_NOWINPATH: 1 + CHERE_INVOKING: 1 + steps: + - name: Set up Cygwin + uses: cygwin/cygwin-install-action@master + with: + packages: make cmake gcc-g++ bash + + - uses: actions/checkout@v6 + + - name: build + run: make + + - name: stats + run: make stats + + - name: cxxtest + run: | + make cxxtest + + - name: test + run: make test + + - name: test api + run: | + ./build/api-test + + openbsd: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: build + test + uses: vmactions/openbsd-vm@v1 + with: + usesh: true + prepare: | + pkg_add cmake gmake + run: | + gmake + gmake stats + + freebsd: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: build + test + uses: vmactions/freebsd-vm@v1 + with: + usesh: true + prepare: | + pkg install -y cmake gmake + run: | + gmake + gmake stats + + android: + runs-on: ubuntu-latest + container: reactnativecommunity/react-native-android:v13.0 + steps: + - uses: actions/checkout@v6 + - name: Configure android arm64 + # see build options you can use in https://developer.android.com/ndk/guides/cmake + run: | + mkdir build + cd build + "$ANDROID_HOME/cmake/3.22.1/bin/cmake" "-DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/26.0.10792818/build/cmake/android.toolchain.cmake" -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-24 -DQJS_BUILD_LIBC=ON .. + - name: Build android arm64 + run: | + "$ANDROID_HOME/cmake/3.22.1/bin/cmake" --build build --target qjs + ls -lh build + + ios: + runs-on: macos-latest + steps: + - uses: actions/checkout@v6 + - name: configure + run: | + cmake -B build -GXcode -DCMAKE_SYSTEM_NAME:STRING=iOS -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED:BOOL=NO -DQJS_BUILD_LIBC=ON + - name: build + run: | + cmake --build build --config Release --target qjs + ls -lh build + + mimalloc-linux: + runs-on: ubuntu-24.04 + env: + QJS_BUILD_CLI_WITH_MIMALLOC: ON + MIMALLOC_SHOW_STATS: 1 + steps: + - uses: actions/checkout@v6 + - name: install dependencies + run: | + sudo apt update && sudo apt -y install libmimalloc-dev + - name: build + run: | + make + - name: cxxtest + run: | + make cxxtest + - name: test + run: | + make test + + mimalloc-macos: + runs-on: macos-latest + env: + QJS_BUILD_CLI_WITH_STATIC_MIMALLOC: ON + MIMALLOC_SHOW_STATS: 1 + steps: + - uses: actions/checkout@v6 + - name: install dependencies + run: | + brew install mimalloc + - name: build + run: | + make + - name: cxxtest + run: | + make cxxtest + - name: test + run: | + make test + + amalgam: + strategy: + matrix: + # TODO(bnoordhuis) test on windows + config: + - { os: ubuntu-latest } + - { os: macos-latest } + runs-on: ${{ matrix.config.os }} + steps: + - uses: actions/checkout@v6 + - name: build + run: | + make + - name: create amalgamation + run: | + make amalgam + - name: build amalgamation + run: | + unzip -d "$RUNNER_TEMP" build/quickjs-amalgam.zip + cc -Wall -I. -o "$RUNNER_TEMP/run-test262.o" -c run-test262.c + cc -Wall -I/ -DQJS_BUILD_LIBC -o "$RUNNER_TEMP/quickjs-amalgam.o" -c "$RUNNER_TEMP/quickjs-amalgam.c" + cc -o "$RUNNER_TEMP/run-test262" "$RUNNER_TEMP/run-test262.o" "$RUNNER_TEMP/quickjs-amalgam.o" -lm + - name: test + run: | + make test RUN262="$RUNNER_TEMP/run-test262" + + jscheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: jscheck + run: | + make jscheck + + parserless: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: build + run: | + make QJS_DISABLE_PARSER=ON QJS_BUILD_EXAMPLES=ON + - name: test + run: | + ./build/hello + ./build/hello_module + + + meson: + runs-on: ${{ matrix.platform }} + name: meson on ${{ matrix.platform }} (${{ matrix.mode.name }} ${{ matrix.flavor }}, ${{ matrix.features.name }}) + strategy: + fail-fast: false + matrix: + flavor: + - debug + - release + features: + - name: default + args: "" + - name: libc + args: -Dlibc=true + - name: mimalloc + args: -Dcli_mimalloc=auto + mode: + - name: default + args: -Dtests=enabled + extra_envs: {} + + # Alternative compiler setups + - name: gcc + args: -Dtests=enabled + extra_envs: + CC: gcc + CXX: g++ + - name: clang + args: -Dtests=enabled + extra_envs: + CC: clang + CXX: clang++ + + - name: sanitize + args: >- + "-Db_sanitize=address,undefined" + extra_envs: {} + + # This is for MSVC, which only supports AddressSanitizer. + # https://learn.microsoft.com/en-us/cpp/sanitizers/ + - name: sanitize+asanonly + args: -Db_sanitize=address + extra_envs: + ASAN_OPTIONS: report_globals=0:halt_on_error=1:abort_on_error=1:print_summary=1 + + - name: clang+sanitize + args: >- + "-Db_sanitize=address,undefined" + extra_envs: + CC: clang + CXX: clang++ + - name: clang+msan + args: -Db_sanitize=memory + extra_envs: + CC: clang + CXX: clang++ + + # default clang on GitHub hosted runners is from MSYS2. + # Use Visual Studio supplied clang-cl instead. + - name: clang-cl+sanitize + args: >- + "-Db_sanitize=address,undefined" + extra_envs: + CC: clang-cl + CXX: clang-cl + platform: + - ubuntu-latest + - windows-latest + - macos-latest + + exclude: + # clang-cl only makes sense on windows. + - platform: ubuntu-latest + mode: + name: clang-cl+sanitize + - platform: macos-latest + mode: + name: clang-cl+sanitize + + # Use clang-cl instead of MSYS2 clang. + # + # we already tested clang+sanitize on linux, + # if this doesn't work, it should be an issue for MSYS2 team to consider. + - platform: windows-latest + mode: + name: clang + - platform: windows-latest + mode: + name: clang+sanitize + - platform: windows-latest + mode: + name: clang+msan + + # MSVC-only sanitizers + - platform: ubuntu-latest + mode: + name: sanitize+asanonly + - platform: macos-latest + mode: + name: sanitize+asanonly + - platform: windows-latest + mode: + name: sanitize + + # clang is the default on macos + # also gcc is an alias to clang + - platform: macos-latest + mode: + name: clang + - platform: macos-latest + mode: + name: gcc + + # gcc is the default on linux + - platform: ubuntu-latest + mode: + name: gcc + + # only run sanitizer tests on linux + # + # gcc/clang's codegen shouldn't massively change across platforms, + # and linux supports most of the sanitizers. + - platform: macos-latest + mode: + name: clang+sanitize + - platform: macos-latest + mode: + # macos does not support msan + name: clang+msan + - platform: macos-latest + mode: + name: sanitize + + steps: + - name: Setup meson + run: | + pipx install meson ninja + - name: Install mimalloc + if: ${{ matrix.platform == 'ubuntu-latest' && matrix.features.name == 'mimalloc' }} + run: sudo apt update && sudo apt -y install libmimalloc-dev + - name: Install mimalloc + if: ${{ matrix.platform == 'macos-latest' && matrix.features.name == 'mimalloc' }} + run: brew install mimalloc + # TODO: Install mimalloc on Windows + # You need to: + # - checkout mimalloc + # - `msbuild mimalloc\ide\vs2022\mimalloc.sln` + # - not cmake, because https://github.com/microsoft/mimalloc/issues/575#issuecomment-1112723975 + # - it is possible to integrate vcpkg with meson, but: + # - 1. the above issue + # - 2. the vcpkg port of mimalloc is outdated, and still broken on server 2019 + # - or maintain a meson port for mimalloc (and ensure it behaves correctly) + # - Make it findable with cmake + # - not the simpler pkg-config. although there was pkg-config in PATH, + # but that was from strawberry perl and thus broken + # ... good job, microsoft :)))) + + - name: Checkout + uses: actions/checkout@v6 + - name: Activate MSVC and Configure + if: ${{ matrix.platform == 'windows-latest' }} + env: ${{ matrix.mode.extra_envs }} + run: | + meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} ${{ matrix.features.args }} --vsenv + - name: Configuring + if: ${{ matrix.platform != 'windows-latest' }} + env: ${{ matrix.mode.extra_envs }} + run: | + meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} ${{ matrix.features.args }} + - name: Building + run: | + meson compile -C build-${{ matrix.flavor }} + + - name: Running tests + env: ${{ matrix.mode.extra_envs }} + run: | + meson test -C build-${{ matrix.flavor }} --timeout-multiplier 5 --print-errorlogs + meson test --benchmark -C build-${{ matrix.flavor }} --timeout-multiplier 5 --print-errorlogs + - uses: actions/upload-artifact@v6 + if: ${{ failure() }} + with: + name: ${{ matrix.platform }}-${{ matrix.mode.name }}-${{ matrix.features.name }}-${{ matrix.flavor }}-logs + path: build-${{ matrix.flavor }}/meson-logs diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/docs.yml b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/docs.yml new file mode 100644 index 0000000..93922e4 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/docs.yml @@ -0,0 +1,49 @@ +name: Docs + +on: + push: + branches: + - master + paths: + - 'docs/**' + - '.github/workflows/*docs.yml' + +jobs: + build: + name: Build Docusaurus + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version-file: 'docs/.nvmrc' + - name: Install dependencies + working-directory: ./docs + run: npm install + - name: Build + working-directory: ./docs + run: npm run build + - name: Upload Build Artifact + uses: actions/upload-pages-artifact@v4 + with: + path: docs/build + + deploy: + name: Deploy to GitHub Pages + needs: build + + # Grant GITHUB_TOKEN the permissions required to make a Pages deployment + permissions: + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source + + # Deploy to the github-pages environment + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/release.yml b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/release.yml new file mode 100644 index 0000000..e97b23c --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/release.yml @@ -0,0 +1,155 @@ +name: release + +on: + pull_request: + push: + tags: + - "v*.*.*" + +jobs: + check_meson_version: + runs-on: ubuntu-22.04 + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + steps: + - uses: actions/checkout@v6 + - name: install meson and ninja + run: | + pip install --upgrade meson ninja + - name: check meson version + run: | + MESON_VERSION=$(meson introspect meson.build --projectinfo | jq -r '.version') + test "${{ github.ref_name }}" = "v${MESON_VERSION}" + + linux: + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + arch: [aarch64, riscv64, x86, x86_64] + steps: + - uses: actions/checkout@v6 + - uses: jirutka/setup-alpine@v1 + with: + arch: ${{matrix.arch}} + packages: "build-base make cmake" + - name: build + shell: alpine.sh {0} + run: | + mkdir build + cd build + cmake -DQJS_BUILD_CLI_STATIC=ON .. + cd .. + cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN) + cmake --build build --target qjsc -j$(getconf _NPROCESSORS_ONLN) + mv build/qjs build/qjs-linux-${{matrix.arch}} + mv build/qjsc build/qjsc-linux-${{matrix.arch}} + - name: check + shell: alpine.sh {0} + run: | + file build/*-linux-${{matrix.arch}} + - name: upload + uses: actions/upload-artifact@v6 + with: + name: qjs-linux-${{matrix.arch}} + path: build/*-linux-${{matrix.arch}} + + macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v6 + - name: build + run: | + mkdir build + cd build + cmake -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" .. + make -j$(getconf _NPROCESSORS_ONLN) + make -C .. amalgam # writes build/quickjs-amalgam.zip + mv qjs qjs-darwin + mv qjsc qjsc-darwin + - name: check + run: | + lipo -info build/qjs-darwin build/qjsc-darwin + - name: upload amalgamation + uses: actions/upload-artifact@v6 + with: + name: quickjs-amalgam.zip + path: build/quickjs-amalgam.zip + compression-level: 0 # already compressed + - name: upload + uses: actions/upload-artifact@v6 + with: + name: qjs-darwin + path: build/*-darwin + + windows: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + arch: [x86, x86_64] + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/checkout@v6 + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.arch == 'x86' && 'mingw32' || 'ucrt64' }} + install: >- + git + make + pacboy: >- + cmake:p + ninja:p + toolchain:p + - name: build + run: | + make + mv build/qjs.exe build/qjs-windows-${{matrix.arch}}.exe + mv build/qjsc.exe build/qjsc-windows-${{matrix.arch}}.exe + - name: check + run: | + file build/qjs-windows-${{matrix.arch}}.exe + ldd build/qjs-windows-${{matrix.arch}}.exe build/qjsc-windows-${{matrix.arch}}.exe + - name: upload + uses: actions/upload-artifact@v6 + with: + name: qjs-windows-${{matrix.arch}} + path: build/*-windows-${{matrix.arch}}.exe + + wasi: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v6 + - name: setup wasi-sdk + run: | + wget -nv https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.deb -P /tmp + sudo apt install /tmp/wasi-sdk*.deb + - name: build + run: | + cmake -B build -DCMAKE_TOOLCHAIN_FILE=/opt/wasi-sdk/share/cmake/wasi-sdk.cmake + make -C build qjs_exe + mv build/qjs build/qjs-wasi.wasm + - name: upload + uses: actions/upload-artifact@v6 + with: + name: qjs-wasi + path: build/qjs-wasi.wasm + + upload-to-release: + needs: [linux, macos, windows, wasi, check_meson_version] + runs-on: ubuntu-22.04 + steps: + - name: get assets + uses: actions/download-artifact@v7 + with: + path: build + merge-multiple: true + - run: ls -R build + - name: release + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + uses: softprops/action-gh-release@v2 + with: + files: | + build/* diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/test-docs.yml b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/test-docs.yml new file mode 100644 index 0000000..9572d20 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/test-docs.yml @@ -0,0 +1,23 @@ +name: Test Docs + +on: + pull_request: + paths: + - 'docs/**' + - '.github/workflows/*docs.yml' + +jobs: + test-docs: + name: Test Docusaurus build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version-file: 'docs/.nvmrc' + - name: Install dependencies + working-directory: ./docs + run: npm install + - name: Build + working-directory: ./docs + run: npm run build diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/tsan.yml b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/tsan.yml new file mode 100644 index 0000000..383b69a --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/tsan.yml @@ -0,0 +1,32 @@ +name: tsan + +on: + push: + branches: + - master + paths: + - '**' + - '!.gitignore' + - '!LICENSE' + - '!README.md' + - '!docs/**' + - '!examples/**' + - '.github/workflows/tsan.yml' + - '.github/workflows/valgrind.yml' + workflow_dispatch: + +jobs: + linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: true + - name: build + run: | + cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DQJS_ENABLE_TSAN=ON + cmake --build build -j`nproc` + - name: test + run: | + git submodule update --init --checkout --depth 1 + ./build/run-test262 -m -c test262.conf -c test262-fast.conf -a diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/valgrind.yml b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/valgrind.yml new file mode 100644 index 0000000..c135639 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.github/workflows/valgrind.yml @@ -0,0 +1,33 @@ +name: valgrind + +on: + push: + branches: + - master + paths: + - '**' + - '!.gitignore' + - '!LICENSE' + - '!README.md' + - '!docs/**' + - '!examples/**' + - '.github/workflows/tsan.yml' + - '.github/workflows/valgrind.yml' + workflow_dispatch: + +jobs: + linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: true + - name: install valgrind + run: sudo apt-get update && sudo apt-get install valgrind + - name: build + run: | + make BUILD_TYPE=RelWithDebInfo + - name: test + run: | + git submodule update --init --checkout --depth 1 + valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --error-exitcode=1 ./build/run-test262 -m -c test262.conf -c test262-fast.conf -a diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.gitignore b/host/cred-script/vendor/rquickjs-sys/quickjs/.gitignore new file mode 100644 index 0000000..ff10fcd --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.gitignore @@ -0,0 +1,14 @@ +*.a +*.orig +*.so +.obj/ +build/ +unicode/ +.idea +cmake-* +.vs +out/ +CMakeUserPresets.json +fuzz +.vscode/ +microbench*.txt diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/.gitmodules b/host/cred-script/vendor/rquickjs-sys/quickjs/.gitmodules new file mode 100644 index 0000000..91828e0 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/.gitmodules @@ -0,0 +1,5 @@ +[submodule "test262"] + path = test262 + url = https://github.com/tc39/test262 + shallow = true + update = none diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/CMakeLists.txt b/host/cred-script/vendor/rquickjs-sys/quickjs/CMakeLists.txt new file mode 100644 index 0000000..f2ada27 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/CMakeLists.txt @@ -0,0 +1,461 @@ +cmake_minimum_required(VERSION 3.10) + +project(quickjs LANGUAGES C) + +include(CheckCCompilerFlag) +include(GNUInstallDirs) + +set(CMAKE_C_VISIBILITY_PRESET hidden) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) +set(CMAKE_C_STANDARD 11) + +# MINGW doesn't exist in older cmake versions, newer versions don't know +# about CMAKE_COMPILER_IS_MINGW, and there is no unique CMAKE_C_COMPILER_ID +# for mingw-based compilers... +if(MINGW) + # do nothing +elseif(CMAKE_C_COMPILER MATCHES "mingw") + set(MINGW TRUE) +else() + set(MINGW FALSE) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "tvOS") + set(TVOS TRUE) +else() + set(TVOS FALSE) +endif() +if(CMAKE_SYSTEM_NAME STREQUAL "watchOS") + set(WATCHOS TRUE) +else() + set(WATCHOS FALSE) +endif() + +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, default to Release") + set(CMAKE_BUILD_TYPE "Release") +endif() + +message(STATUS "Building in ${CMAKE_BUILD_TYPE} mode") +message(STATUS "Building with ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} on ${CMAKE_SYSTEM}") + +macro(xcheck_add_c_compiler_flag FLAG) + string(REPLACE "-" "" FLAG_NO_HYPHEN ${FLAG}) + check_c_compiler_flag(${FLAG} COMPILER_SUPPORTS_${FLAG_NO_HYPHEN}) + if(COMPILER_SUPPORTS_${FLAG_NO_HYPHEN}) + add_compile_options(${FLAG}) + endif() +endmacro() + +xcheck_add_c_compiler_flag(-Wall) +if(NOT MSVC AND NOT IOS AND NOT TVOS AND NOT WATCHOS) + xcheck_add_c_compiler_flag(-Werror) + xcheck_add_c_compiler_flag(-Wextra) +endif() +xcheck_add_c_compiler_flag(-Wformat=2) +xcheck_add_c_compiler_flag(-Wno-implicit-fallthrough) +xcheck_add_c_compiler_flag(-Wno-sign-compare) +xcheck_add_c_compiler_flag(-Wno-missing-field-initializers) +xcheck_add_c_compiler_flag(-Wno-unused-parameter) +xcheck_add_c_compiler_flag(-Wno-unused-but-set-variable) +xcheck_add_c_compiler_flag(-Wno-unused-result) +xcheck_add_c_compiler_flag(-Wno-stringop-truncation) +xcheck_add_c_compiler_flag(-Wno-array-bounds) +xcheck_add_c_compiler_flag(-funsigned-char) + +# ClangCL is command line compatible with MSVC, so 'MSVC' is set. +if(MSVC) + xcheck_add_c_compiler_flag(-Wno-unsafe-buffer-usage) + xcheck_add_c_compiler_flag(-Wno-sign-conversion) + xcheck_add_c_compiler_flag(-Wno-nonportable-system-include-path) + xcheck_add_c_compiler_flag(-Wno-implicit-int-conversion) + xcheck_add_c_compiler_flag(-Wno-shorten-64-to-32) + xcheck_add_c_compiler_flag(-Wno-reserved-macro-identifier) + xcheck_add_c_compiler_flag(-Wno-reserved-identifier) + xcheck_add_c_compiler_flag(-Wdeprecated-declarations) + xcheck_add_c_compiler_flag(/experimental:c11atomics) + xcheck_add_c_compiler_flag(/wd4018) # -Wno-sign-conversion + xcheck_add_c_compiler_flag(/wd4061) # -Wno-implicit-fallthrough + xcheck_add_c_compiler_flag(/wd4100) # -Wno-unused-parameter + xcheck_add_c_compiler_flag(/wd4200) # -Wno-zero-length-array + xcheck_add_c_compiler_flag(/wd4242) # -Wno-shorten-64-to-32 + xcheck_add_c_compiler_flag(/wd4244) # -Wno-shorten-64-to-32 + xcheck_add_c_compiler_flag(/wd4245) # -Wno-sign-compare + xcheck_add_c_compiler_flag(/wd4267) # -Wno-shorten-64-to-32 + xcheck_add_c_compiler_flag(/wd4388) # -Wno-sign-compare + xcheck_add_c_compiler_flag(/wd4389) # -Wno-sign-compare + xcheck_add_c_compiler_flag(/wd4456) # Hides previous local declaration + xcheck_add_c_compiler_flag(/wd4457) # Hides function parameter + xcheck_add_c_compiler_flag(/wd4710) # Function not inlined + xcheck_add_c_compiler_flag(/wd4711) # Function was inlined + xcheck_add_c_compiler_flag(/wd4820) # Padding added after construct + xcheck_add_c_compiler_flag(/wd4996) # -Wdeprecated-declarations + xcheck_add_c_compiler_flag(/wd5045) # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +endif() + +# Set a 8MB default stack size on Windows. +# It defaults to 1MB on MSVC, which is the same as our current JS stack size, +# so it will overflow and crash otherwise. +# On MinGW it defaults to 2MB. +if(WIN32) + if(MSVC) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8388608") + else() + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,8388608") + endif() +endif() + +# MacOS and GCC 11 or later need -Wno-maybe-uninitialized +# https://github.com/quickjs-ng/quickjs/issues/453 +if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11) + xcheck_add_c_compiler_flag(-Wno-maybe-uninitialized) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "WASI") + add_compile_definitions( + _WASI_EMULATED_PROCESS_CLOCKS + _WASI_EMULATED_SIGNAL + ) + add_link_options( + -lwasi-emulated-process-clocks + -lwasi-emulated-signal + ) +endif() + +if(CMAKE_BUILD_TYPE MATCHES "Debug") + xcheck_add_c_compiler_flag(/Od) + xcheck_add_c_compiler_flag(-O0) + xcheck_add_c_compiler_flag(-ggdb) + xcheck_add_c_compiler_flag(-fno-omit-frame-pointer) +endif() + +macro(xoption OPTION_NAME OPTION_TEXT OPTION_DEFAULT) + option(${OPTION_NAME} ${OPTION_TEXT} ${OPTION_DEFAULT}) + if(DEFINED ENV{${OPTION_NAME}}) + # Allow setting the option through an environment variable. + set(${OPTION_NAME} $ENV{${OPTION_NAME}}) + endif() + if(${OPTION_NAME}) + add_definitions(-D${OPTION_NAME}) + endif() + message(STATUS " ${OPTION_NAME}: ${${OPTION_NAME}}") +endmacro() + +xoption(BUILD_SHARED_LIBS "Build a shared library" OFF) +if(BUILD_SHARED_LIBS) + message(STATUS "Building a shared library") +endif() + +# note: QJS_ENABLE_TSAN is currently incompatible with the other sanitizers but we +# don't explicitly check for that because who knows what the future will bring? +# QJS_ENABLE_MSAN only works with clang at the time of writing; also not checked +# for the same reason +xoption(QJS_BUILD_EXAMPLES "Build examples" OFF) +xoption(QJS_BUILD_CLI_STATIC "Build a static qjs executable" OFF) +xoption(QJS_BUILD_CLI_WITH_MIMALLOC "Build the qjs executable with mimalloc" OFF) +xoption(QJS_BUILD_CLI_WITH_STATIC_MIMALLOC "Build the qjs executable with mimalloc (statically linked)" OFF) +xoption(QJS_DISABLE_PARSER "Disable JS source code parser" OFF) +xoption(QJS_ENABLE_ASAN "Enable AddressSanitizer (ASan)" OFF) +xoption(QJS_ENABLE_MSAN "Enable MemorySanitizer (MSan)" OFF) +xoption(QJS_ENABLE_TSAN "Enable ThreadSanitizer (TSan)" OFF) +xoption(QJS_ENABLE_UBSAN "Enable UndefinedBehaviorSanitizer (UBSan)" OFF) + +if(QJS_ENABLE_ASAN) +message(STATUS "Building with ASan") +add_compile_options( + -fsanitize=address + -fno-sanitize-recover=all + -fno-omit-frame-pointer +) +add_link_options( + -fsanitize=address + -fno-sanitize-recover=all + -fno-omit-frame-pointer +) +endif() + +if(QJS_ENABLE_MSAN) +message(STATUS "Building with MSan") +add_compile_options( + -fsanitize=memory + -fno-sanitize-recover=all + -fno-omit-frame-pointer +) +add_link_options( + -fsanitize=memory + -fno-sanitize-recover=all + -fno-omit-frame-pointer +) +endif() + +if(QJS_ENABLE_TSAN) +message(STATUS "Building with TSan") +add_compile_options( + -fsanitize=thread + -fno-sanitize-recover=all + -fno-omit-frame-pointer +) +add_link_options( + -fsanitize=thread + -fno-sanitize-recover=all + -fno-omit-frame-pointer +) +endif() + +if(QJS_ENABLE_UBSAN) +message(STATUS "Building with UBSan") +add_compile_options( + -fsanitize=undefined + -fno-sanitize-recover=all + -fno-omit-frame-pointer +) +add_link_options( + -fsanitize=undefined + -fno-sanitize-recover=all + -fno-omit-frame-pointer +) +endif() + + +# QuickJS library +# + +xoption(QJS_BUILD_LIBC "Build standard library modules as part of the library" OFF) +macro(add_qjs_libc_if_needed target) + if(NOT QJS_BUILD_LIBC) + target_sources(${target} PRIVATE quickjs-libc.c) + endif() +endmacro() +macro(add_static_if_needed target) + if(QJS_BUILD_CLI_STATIC OR MINGW) + target_link_options(${target} PRIVATE -static) + if(MINGW) + target_link_options(${target} PRIVATE -static-libgcc) + endif() + endif() +endmacro() + +set(qjs_sources + cutils.c + dtoa.c + libregexp.c + libunicode.c + quickjs.c +) + +if(QJS_BUILD_LIBC) + list(APPEND qjs_sources quickjs-libc.c) +endif() +list(APPEND qjs_defines _GNU_SOURCE) +if(WIN32) + # NB: Windows 7 is EOL and we are only supporting in so far as it doesn't interfere with progress. + list(APPEND qjs_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0601) +endif() +if(TVOS) + list(APPEND qjs_defines _TVOS) +endif() +if(WATCHOS) + list(APPEND qjs_defines _WATCHOS) +endif() +list(APPEND qjs_libs ${CMAKE_DL_LIBS}) +find_package(Threads) +if(NOT CMAKE_SYSTEM_NAME STREQUAL "WASI") + list(APPEND qjs_libs ${CMAKE_THREAD_LIBS_INIT}) +endif() + +# try to find libm +find_library(M_LIBRARIES m) +if(M_LIBRARIES OR CMAKE_C_COMPILER_ID STREQUAL "TinyCC") + list(APPEND qjs_libs m) +endif() + +add_library(qjs ${qjs_sources}) +target_compile_definitions(qjs PRIVATE ${qjs_defines}) +target_include_directories(qjs PUBLIC + $ + $ +) +target_link_libraries(qjs PUBLIC ${qjs_libs}) + +if(EMSCRIPTEN) + add_executable(qjs_wasm ${qjs_sources}) + target_link_options(qjs_wasm PRIVATE + # in emscripten 3.x, this will be set to 16k which is too small for quickjs. #write sth. to force github rebuild + -sSTACK_SIZE=2097152 # let it be 2m = 2 * 1024 * 1024 = 2097152, otherwise, stack overflow may be occured at bootstrap + -sNO_INVOKE_RUN + -sNO_EXIT_RUNTIME + -sMODULARIZE # do not mess the global + -sEXPORT_ES6 # export js file to morden es module + -sEXPORT_NAME=getQuickJs # give a name + -sTEXTDECODER=1 # it will be 2 if we use -Oz, and that will cause js -> c string convertion fail + -sNO_DEFAULT_TO_CXX # this project is pure c project, no need for c plus plus handle + -sEXPORTED_RUNTIME_METHODS=ccall,cwrap + ) + target_compile_definitions(qjs_wasm PRIVATE ${qjs_defines}) + target_link_libraries(qjs_wasm m) +endif() + + +# QuickJS bytecode compiler +# + +add_executable(qjsc + qjsc.c +) +add_qjs_libc_if_needed(qjsc) +add_static_if_needed(qjsc) +target_compile_definitions(qjsc PRIVATE ${qjs_defines}) +target_link_libraries(qjsc qjs) + + +# QuickJS CLI +# + +add_executable(qjs_exe + gen/repl.c + gen/standalone.c + qjs.c +) +add_qjs_libc_if_needed(qjs_exe) +add_static_if_needed(qjs_exe) +set_target_properties(qjs_exe PROPERTIES + OUTPUT_NAME "qjs" +) +target_compile_definitions(qjs_exe PRIVATE ${qjs_defines}) +target_link_libraries(qjs_exe qjs) +if(NOT WIN32) + set_target_properties(qjs_exe PROPERTIES ENABLE_EXPORTS TRUE) +endif() +if(QJS_BUILD_CLI_WITH_MIMALLOC OR QJS_BUILD_CLI_WITH_STATIC_MIMALLOC) + find_package(mimalloc REQUIRED) + # Upstream mimalloc doesn't provide a way to know if both libraries are supported. + if(QJS_BUILD_CLI_WITH_STATIC_MIMALLOC) + target_link_libraries(qjs_exe mimalloc-static) + else() + target_link_libraries(qjs_exe mimalloc) + endif() +endif() + +# Test262 runner +# + +if(NOT EMSCRIPTEN) + add_executable(run-test262 + run-test262.c + ) + add_qjs_libc_if_needed(run-test262) + target_compile_definitions(run-test262 PRIVATE ${qjs_defines}) + target_link_libraries(run-test262 qjs) +endif() + +# Interrupt test +# + +add_executable(api-test + api-test.c +) +target_compile_definitions(api-test PRIVATE ${qjs_defines}) +target_link_libraries(api-test qjs) + +# Unicode generator +# + +add_executable(unicode_gen EXCLUDE_FROM_ALL + cutils.c + libunicode.c + unicode_gen.c +) +target_compile_definitions(unicode_gen PRIVATE ${qjs_defines}) + +add_executable(function_source + gen/function_source.c +) +add_qjs_libc_if_needed(function_source) +target_include_directories(function_source PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_definitions(function_source PRIVATE ${qjs_defines}) +target_link_libraries(function_source qjs) + +# Examples +# + +if(QJS_BUILD_EXAMPLES) + add_executable(hello + gen/hello.c + ) + add_qjs_libc_if_needed(hello) + target_include_directories(hello PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + target_compile_definitions(hello PRIVATE ${qjs_defines}) + target_link_libraries(hello qjs) + + add_executable(hello_module + gen/hello_module.c + ) + add_qjs_libc_if_needed(hello_module) + target_include_directories(hello_module PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + target_compile_definitions(hello_module PRIVATE ${qjs_defines}) + target_link_libraries(hello_module qjs) + + add_library(fib MODULE examples/fib.c) + set_target_properties(fib PROPERTIES + PREFIX "" + C_VISIBILITY_PRESET default + ) + target_compile_definitions(fib PRIVATE JS_SHARED_LIBRARY) + if(WIN32) + target_link_libraries(fib qjs) + elseif(APPLE) + target_link_options(fib PRIVATE -undefined dynamic_lookup) + endif() + + add_library(point MODULE examples/point.c) + set_target_properties(point PROPERTIES + PREFIX "" + C_VISIBILITY_PRESET default + ) + target_compile_definitions(point PRIVATE JS_SHARED_LIBRARY) + if(WIN32) + target_link_libraries(point qjs) + elseif(APPLE) + target_link_options(point PRIVATE -undefined dynamic_lookup) + endif() + + add_executable(test_fib + examples/fib.c + gen/test_fib.c + ) + add_qjs_libc_if_needed(test_fib) + target_include_directories(test_fib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + target_compile_definitions(test_fib PRIVATE ${qjs_defines}) + target_link_libraries(test_fib qjs) +endif() + +# Install target +# + +file(STRINGS quickjs.h quickjs_h REGEX QJS_VERSION) +string(REGEX MATCH "QJS_VERSION_MAJOR ([0-9]*)" _ "${quickjs_h}") +set(QJS_VERSION_MAJOR ${CMAKE_MATCH_1}) +string(REGEX MATCH "QJS_VERSION_MINOR ([0-9]*)" _ "${quickjs_h}") +set(QJS_VERSION_MINOR ${CMAKE_MATCH_1}) +string(REGEX MATCH "QJS_VERSION_PATCH ([0-9]*)" _ "${quickjs_h}") +set(QJS_VERSION_PATCH ${CMAKE_MATCH_1}) +set_target_properties(qjs PROPERTIES + VERSION ${QJS_VERSION_MAJOR}.${QJS_VERSION_MINOR}.${QJS_VERSION_PATCH} + SOVERSION ${QJS_VERSION_MAJOR} +) +install(FILES quickjs.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +if(QJS_BUILD_LIBC) + install(FILES quickjs-libc.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif() +if(NOT IOS AND NOT TVOS AND NOT WATCHOS) + install(TARGETS qjs_exe RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + install(TARGETS qjsc RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() +install(TARGETS qjs EXPORT qjsConfig + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(EXPORT qjsConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/quickjs) +install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) +install(DIRECTORY examples DESTINATION ${CMAKE_INSTALL_DOCDIR}) diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/LICENSE b/host/cred-script/vendor/rquickjs-sys/quickjs/LICENSE new file mode 100644 index 0000000..3c78b69 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/LICENSE @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Copyright (c) 2017-2024 Fabrice Bellard +Copyright (c) 2017-2024 Charlie Gordon +Copyright (c) 2023-2025 Ben Noordhuis +Copyright (c) 2023-2025 Saúl Ibarra Corretgé + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/Makefile b/host/cred-script/vendor/rquickjs-sys/quickjs/Makefile new file mode 100644 index 0000000..4ff8ca1 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/Makefile @@ -0,0 +1,147 @@ +# +# QuickJS Javascript Engine +# +# Copyright (c) 2017-2024 Fabrice Bellard +# Copyright (c) 2017-2024 Charlie Gordon +# Copyright (c) 2023-2025 Ben Noordhuis +# Copyright (c) 2023-2025 Saúl Ibarra Corretgé +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +BUILD_DIR=build +BUILD_TYPE?=Release +INSTALL_PREFIX?=/usr/local + +QJS=$(BUILD_DIR)/qjs +QJSC=$(BUILD_DIR)/qjsc +RUN262=$(BUILD_DIR)/run-test262 + +JOBS?=$(shell getconf _NPROCESSORS_ONLN) +ifeq ($(JOBS),) +JOBS := $(shell sysctl -n hw.ncpu) +endif +ifeq ($(JOBS),) +JOBS := $(shell nproc) +endif +ifeq ($(JOBS),) +JOBS := 4 +endif + +all: $(QJS) + +amalgam: TEMP := $(shell mktemp -d) +amalgam: $(QJS) + $(QJS) amalgam.js $(TEMP)/quickjs-amalgam.c + cp quickjs.h quickjs-libc.h $(TEMP) + cd $(TEMP) && zip -9 quickjs-amalgam.zip quickjs-amalgam.c quickjs.h quickjs-libc.h + cp $(TEMP)/quickjs-amalgam.zip $(BUILD_DIR) + cd $(TEMP) && $(RM) quickjs-amalgam.zip quickjs-amalgam.c quickjs.h quickjs-libc.h + $(RM) -d $(TEMP) + +fuzz: + clang -g -O1 -fsanitize=address,undefined,fuzzer -o fuzz fuzz.c + ./fuzz + +$(BUILD_DIR): + cmake -B $(BUILD_DIR) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DCMAKE_INSTALL_PREFIX=$(INSTALL_PREFIX) + +$(QJS): $(BUILD_DIR) + cmake --build $(BUILD_DIR) -j $(JOBS) + +$(QJSC): $(BUILD_DIR) + cmake --build $(BUILD_DIR) --target qjsc -j $(JOBS) + +install: $(QJS) $(QJSC) + cmake --build $(BUILD_DIR) --target install + +clean: + cmake --build $(BUILD_DIR) --target clean + +codegen: $(QJSC) + $(QJSC) -ss -o gen/repl.c -m repl.js + $(QJSC) -ss -o gen/standalone.c -m standalone.js + $(QJSC) -e -o gen/function_source.c tests/function_source.js + $(QJSC) -e -o gen/hello.c examples/hello.js + $(QJSC) -e -o gen/hello_module.c -m examples/hello_module.js + $(QJSC) -e -o gen/test_fib.c -m examples/test_fib.js + $(QJSC) -C -ss -o builtin-array-fromasync.h builtin-array-fromasync.js + +debug: + BUILD_TYPE=Debug $(MAKE) + +distclean: + @rm -rf $(BUILD_DIR) + +stats: $(QJS) + $(QJS) -qd + +jscheck: CFLAGS=-I. -D_GNU_SOURCE -DJS_CHECK_JSVALUE -Wall -Werror -fsyntax-only -c -o /dev/null +jscheck: + $(CC) $(CFLAGS) api-test.c + $(CC) $(CFLAGS) ctest.c + $(CC) $(CFLAGS) fuzz.c + $(CC) $(CFLAGS) gen/function_source.c + $(CC) $(CFLAGS) gen/hello.c + $(CC) $(CFLAGS) gen/hello_module.c + $(CC) $(CFLAGS) gen/repl.c + $(CC) $(CFLAGS) gen/standalone.c + $(CC) $(CFLAGS) gen/test_fib.c + $(CC) $(CFLAGS) qjs.c + $(CC) $(CFLAGS) qjsc.c + $(CC) $(CFLAGS) quickjs-libc.c + $(CC) $(CFLAGS) quickjs.c + $(CC) $(CFLAGS) run-test262.c + +# effectively .PHONY because it doesn't generate output +ctest: CFLAGS=-std=c11 -fsyntax-only -Wall -Wextra -Werror -pedantic +ctest: ctest.c quickjs.h + $(CC) $(CFLAGS) -DJS_NAN_BOXING=0 $< + $(CC) $(CFLAGS) -DJS_NAN_BOXING=1 $< + +# effectively .PHONY because it doesn't generate output +cxxtest: CXXFLAGS=-std=c++11 -fsyntax-only -Wall -Wextra -Werror -pedantic +cxxtest: cxxtest.cc quickjs.h + $(CXX) $(CXXFLAGS) -DJS_NAN_BOXING=0 $< + $(CXX) $(CXXFLAGS) -DJS_NAN_BOXING=1 $< + +test: $(QJS) + $(RUN262) -c tests.conf + +test262: $(QJS) + $(RUN262) -m -c test262.conf -a + +test262-fast: $(QJS) + $(RUN262) -m -c test262.conf -c test262-fast.conf -a + +test262-update: $(QJS) + $(RUN262) -u -c test262.conf -a -t 1 + +test262-check: $(QJS) + $(RUN262) -m -c test262.conf -E -a + +microbench: $(QJS) + $(QJS) tests/microbench.js + +unicode_gen: $(BUILD_DIR) + cmake --build $(BUILD_DIR) --target unicode_gen + +libunicode-table.h: unicode_gen + $(BUILD_DIR)/unicode_gen unicode $@ + +.PHONY: all amalgam ctest cxxtest debug fuzz jscheck install clean codegen distclean stats test test262 test262-update test262-check microbench unicode_gen $(QJS) $(QJSC) diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/README.md b/host/cred-script/vendor/rquickjs-sys/quickjs/README.md new file mode 100644 index 0000000..e4b0e34 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/README.md @@ -0,0 +1,24 @@ +# ⚡️ QuickJS - A mighty JavaScript engine + +## Overview + +QuickJS is a small and embeddable JavaScript engine. It aims to support the latest +[ECMAScript] specification. + +This project is a _fork_ of the [original QuickJS project] by Fabrice Bellard and Charlie Gordon, after it went dormant, with the intent of reigniting its development. + +## Getting started + +Head over to the [project website] for instructions on how to get started and more +documentation. + +## Authors + +[@bnoordhuis], [@saghul], and many more [contributors]. + +[ECMAScript]: https://tc39.es/ecma262/ +[original QuickJS project]: https://bellard.org/quickjs +[@bnoordhuis]: https://github.com/bnoordhuis +[@saghul]: https://github.com/saghul +[contributors]: https://github.com/quickjs-ng/quickjs/graphs/contributors +[project website]: https://quickjs-ng.github.io/quickjs/ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/amalgam.js b/host/cred-script/vendor/rquickjs-sys/quickjs/amalgam.js new file mode 100644 index 0000000..028d779 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/amalgam.js @@ -0,0 +1,49 @@ +import {loadFile, writeFile} from "qjs:std" + +const cutils_c = loadFile("cutils.c") +const cutils_h = loadFile("cutils.h") +const dtoa_c = loadFile("dtoa.c") +const dtoa_h = loadFile("dtoa.h") +const libregexp_c = loadFile("libregexp.c") +const libregexp_h = loadFile("libregexp.h") +const libregexp_opcode_h = loadFile("libregexp-opcode.h") +const libunicode_c = loadFile("libunicode.c") +const libunicode_h = loadFile("libunicode.h") +const libunicode_table_h = loadFile("libunicode-table.h") +const list_h = loadFile("list.h") +const quickjs_atom_h = loadFile("quickjs-atom.h") +const quickjs_c = loadFile("quickjs.c") +const quickjs_c_atomics_h = loadFile("quickjs-c-atomics.h") +const quickjs_h = loadFile("quickjs.h") +const quickjs_libc_c = loadFile("quickjs-libc.c") +const quickjs_libc_h = loadFile("quickjs-libc.h") +const quickjs_opcode_h = loadFile("quickjs-opcode.h") +const gen_builtin_array_fromasync_h = loadFile("builtin-array-fromasync.h") + +let source = "#if defined(QJS_BUILD_LIBC) && defined(__linux__) && !defined(_GNU_SOURCE)\n" + + "#define _GNU_SOURCE\n" + + "#endif\n" + + quickjs_c_atomics_h + + cutils_h + + dtoa_h + + list_h + + libunicode_h // exports lre_is_id_start, used by libregexp.h + + libregexp_h + + libunicode_table_h + + quickjs_h + + quickjs_c + + cutils_c + + dtoa_c + + libregexp_c + + libunicode_c + + "#ifdef QJS_BUILD_LIBC\n" + + quickjs_libc_h + + quickjs_libc_c + + "#endif // QJS_BUILD_LIBC\n" +source = source.replace(/#include "quickjs-atom.h"/g, quickjs_atom_h) +source = source.replace(/#include "quickjs-opcode.h"/g, quickjs_opcode_h) +source = source.replace(/#include "libregexp-opcode.h"/g, libregexp_opcode_h) +source = source.replace(/#include "builtin-array-fromasync.h"/g, + gen_builtin_array_fromasync_h) +source = source.replace(/#include "[^"]+"/g, "") +writeFile(execArgv[2] ?? "quickjs-amalgam.c", source) diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/api-test.c b/host/cred-script/vendor/rquickjs-sys/quickjs/api-test.c new file mode 100644 index 0000000..c6e9d21 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/api-test.c @@ -0,0 +1,854 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif +#include +#include +#include +#include "quickjs.h" +#include "cutils.h" + +static JSValue eval(JSContext *ctx, const char *code) +{ + return JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_GLOBAL); +} + +static JSValue cfunc_callback(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + return JS_ThrowTypeError(ctx, "from cfunc"); +} + +static JSValue cfuncdata_callback(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, + int magic, JSValueConst *func_data) +{ + return JS_ThrowTypeError(ctx, "from cfuncdata"); +} + +static JSValue cclosure_callback(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, + int magic, void *func_data) +{ + return JS_ThrowTypeError(ctx, "from cclosure"); +} + +static bool closure_finalized = false; + +static void cclosure_opaque_finalize(void *opaque) +{ + if ((intptr_t)opaque == 12) + closure_finalized = true; +} + +static void cfunctions(void) +{ + uint32_t length; + const char *s; + JSValue ret, stack; + + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + JSValue cfunc = JS_NewCFunction(ctx, cfunc_callback, "cfunc", 42); + JSValue cfuncdata = + JS_NewCFunctionData2(ctx, cfuncdata_callback, "cfuncdata", + /*length*/1337, /*magic*/0, /*data_len*/0, NULL); + JSValue cclosure = + JS_NewCClosure(ctx, cclosure_callback, "cclosure", cclosure_opaque_finalize, + /*length*/0xC0DE, /*magic*/11, /*opaque*/(void*)12); + JSValue global = JS_GetGlobalObject(ctx); + JS_SetPropertyStr(ctx, global, "cfunc", cfunc); + JS_SetPropertyStr(ctx, global, "cfuncdata", cfuncdata); + JS_SetPropertyStr(ctx, global, "cclosure", cclosure); + JS_FreeValue(ctx, global); + + ret = eval(ctx, "cfunc.name"); + assert(!JS_IsException(ret)); + assert(JS_IsString(ret)); + s = JS_ToCString(ctx, ret); + JS_FreeValue(ctx, ret); + assert(s); + assert(!strcmp(s, "cfunc")); + JS_FreeCString(ctx, s); + ret = eval(ctx, "cfunc.length"); + assert(!JS_IsException(ret)); + assert(JS_IsNumber(ret)); + assert(0 == JS_ToUint32(ctx, &length, ret)); + assert(length == 42); + + ret = eval(ctx, "cfuncdata.name"); + assert(!JS_IsException(ret)); + assert(JS_IsString(ret)); + s = JS_ToCString(ctx, ret); + JS_FreeValue(ctx, ret); + assert(s); + assert(!strcmp(s, "cfuncdata")); + JS_FreeCString(ctx, s); + ret = eval(ctx, "cfuncdata.length"); + assert(!JS_IsException(ret)); + assert(JS_IsNumber(ret)); + assert(0 == JS_ToUint32(ctx, &length, ret)); + assert(length == 1337); + + ret = eval(ctx, "cclosure.name"); + assert(!JS_IsException(ret)); + assert(JS_IsString(ret)); + s = JS_ToCString(ctx, ret); + JS_FreeValue(ctx, ret); + assert(s); + assert(!strcmp(s, "cclosure")); + JS_FreeCString(ctx, s); + ret = eval(ctx, "cclosure.length"); + assert(!JS_IsException(ret)); + assert(JS_IsNumber(ret)); + assert(0 == JS_ToUint32(ctx, &length, ret)); + assert(length == 0xC0DE); + + ret = eval(ctx, "cfunc()"); + assert(JS_IsException(ret)); + ret = JS_GetException(ctx); + assert(JS_IsError(ret)); + stack = JS_GetPropertyStr(ctx, ret, "stack"); + assert(JS_IsString(stack)); + s = JS_ToCString(ctx, stack); + JS_FreeValue(ctx, stack); + assert(s); + assert(!strcmp(s, " at cfunc (native)\n at (:1:1)\n")); + JS_FreeCString(ctx, s); + s = JS_ToCString(ctx, ret); + JS_FreeValue(ctx, ret); + assert(s); + assert(!strcmp(s, "TypeError: from cfunc")); + JS_FreeCString(ctx, s); + + ret = eval(ctx, "cfuncdata()"); + assert(JS_IsException(ret)); + ret = JS_GetException(ctx); + assert(JS_IsError(ret)); + stack = JS_GetPropertyStr(ctx, ret, "stack"); + assert(JS_IsString(stack)); + s = JS_ToCString(ctx, stack); + JS_FreeValue(ctx, stack); + assert(s); + assert(!strcmp(s, " at cfuncdata (native)\n at (:1:1)\n")); + JS_FreeCString(ctx, s); + s = JS_ToCString(ctx, ret); + JS_FreeValue(ctx, ret); + assert(s); + assert(!strcmp(s, "TypeError: from cfuncdata")); + JS_FreeCString(ctx, s); + + ret = eval(ctx, "cclosure()"); + assert(JS_IsException(ret)); + ret = JS_GetException(ctx); + assert(JS_IsError(ret)); + stack = JS_GetPropertyStr(ctx, ret, "stack"); + assert(JS_IsString(stack)); + s = JS_ToCString(ctx, stack); + JS_FreeValue(ctx, stack); + assert(s); + assert(!strcmp(s, " at cclosure (native)\n at (:1:1)\n")); + JS_FreeCString(ctx, s); + s = JS_ToCString(ctx, ret); + JS_FreeValue(ctx, ret); + assert(s); + assert(!strcmp(s, "TypeError: from cclosure")); + JS_FreeCString(ctx, s); + + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + + assert(closure_finalized); +} + +#define MAX_TIME 10 + +static int timeout_interrupt_handler(JSRuntime *rt, void *opaque) +{ + int *time = (int *)opaque; + if (*time <= MAX_TIME) + *time += 1; + return *time > MAX_TIME; +} + +static void sync_call(void) +{ + static const char code[] = +"(function() { \ + try { \ + while (true) {} \ + } catch (e) {} \ +})();"; + + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + int time = 0; + JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time); + JSValue ret = eval(ctx, code); + assert(time > MAX_TIME); + assert(JS_IsException(ret)); + JS_FreeValue(ctx, ret); + assert(JS_HasException(ctx)); + JSValue e = JS_GetException(ctx); + assert(JS_IsUncatchableError(e)); + JS_FreeValue(ctx, e); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static void async_call(void) +{ + static const char code[] = +"(async function() { \ + const loop = async () => { \ + await Promise.resolve(); \ + while (true) {} \ + }; \ + await loop().catch(() => {}); \ +})();"; + + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + int time = 0; + JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time); + JSValue ret = eval(ctx, code); + assert(!JS_IsException(ret)); + JS_FreeValue(ctx, ret); + assert(JS_IsJobPending(rt)); + int r = 0; + while (JS_IsJobPending(rt)) { + r = JS_ExecutePendingJob(rt, &ctx); + } + assert(time > MAX_TIME); + assert(r == -1); + assert(JS_HasException(ctx)); + JSValue e = JS_GetException(ctx); + assert(JS_IsUncatchableError(e)); + JS_FreeValue(ctx, e); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static JSValue save_value(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + assert(argc == 1); + JSValue *p = (JSValue *)JS_GetContextOpaque(ctx); + *p = JS_DupValue(ctx, argv[0]); + return JS_UNDEFINED; +} + +static void async_call_stack_overflow(void) +{ + static const char code[] = +"(async function() { \ + const f = () => f(); \ + try { \ + await Promise.resolve(); \ + f(); \ + } catch (e) { \ + save_value(e); \ + } \ +})();"; + + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + JSValue value = JS_UNDEFINED; + JS_SetContextOpaque(ctx, &value); + JSValue global = JS_GetGlobalObject(ctx); + JS_SetPropertyStr(ctx, global, "save_value", JS_NewCFunction(ctx, save_value, "save_value", 1)); + JS_FreeValue(ctx, global); + JSValue ret = eval(ctx, code); + assert(!JS_IsException(ret)); + JS_FreeValue(ctx, ret); + assert(JS_IsJobPending(rt)); + int r = 0; + while (JS_IsJobPending(rt)) { + r = JS_ExecutePendingJob(rt, &ctx); + } + assert(r == 1); + assert(!JS_HasException(ctx)); + assert(JS_IsError(value)); // stack overflow should be caught + JS_FreeValue(ctx, value); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +// https://github.com/quickjs-ng/quickjs/issues/914 +static void raw_context_global_var(void) +{ + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContextRaw(rt); + JS_AddIntrinsicEval(ctx); + { + JSValue ret = eval(ctx, "globalThis"); + assert(JS_IsException(ret)); + JS_FreeValue(ctx, ret); + } + { + JSValue ret = eval(ctx, "var x = 42"); + assert(JS_IsUndefined(ret)); + JS_FreeValue(ctx, ret); + } + { + JSValue ret = eval(ctx, "function f() {}"); + assert(JS_IsUndefined(ret)); + JS_FreeValue(ctx, ret); + } + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static void is_array(void) +{ + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + { + JSValue ret = eval(ctx, "[]"); + assert(!JS_IsException(ret)); + assert(JS_IsArray(ret)); + JS_FreeValue(ctx, ret); + } + { + JSValue ret = eval(ctx, "new Proxy([], {})"); + assert(!JS_IsException(ret)); + assert(!JS_IsArray(ret)); + assert(JS_IsProxy(ret)); + JSValue handler = JS_GetProxyHandler(ctx, ret); + JSValue target = JS_GetProxyTarget(ctx, ret); + assert(!JS_IsException(handler)); + assert(!JS_IsException(target)); + assert(!JS_IsProxy(handler)); + assert(!JS_IsProxy(target)); + assert(JS_IsObject(handler)); + assert(JS_IsArray(target)); + JS_FreeValue(ctx, handler); + JS_FreeValue(ctx, target); + JS_FreeValue(ctx, ret); + } + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static int loader_calls; + +static JSModuleDef *loader(JSContext *ctx, const char *name, void *opaque) +{ + loader_calls++; + assert(!strcmp(name, "b")); + static const char code[] = "export function f(x){}"; + JSValue ret = JS_Eval(ctx, code, strlen(code), "b", + JS_EVAL_TYPE_MODULE|JS_EVAL_FLAG_COMPILE_ONLY); + assert(!JS_IsException(ret)); + JSModuleDef *m = JS_VALUE_GET_PTR(ret); + assert(m); + JS_FreeValue(ctx, ret); + return m; +} + +static void module_serde(void) +{ + JSRuntime *rt = JS_NewRuntime(); + //JS_SetDumpFlags(rt, JS_DUMP_MODULE_RESOLVE); + JS_SetModuleLoaderFunc(rt, NULL, loader, NULL); + JSContext *ctx = JS_NewContext(rt); + static const char code[] = "import {f} from 'b'; f()"; + assert(loader_calls == 0); + JSValue mod = JS_Eval(ctx, code, strlen(code), "a", + JS_EVAL_TYPE_MODULE|JS_EVAL_FLAG_COMPILE_ONLY); + assert(loader_calls == 1); + assert(!JS_IsException(mod)); + assert(JS_IsModule(mod)); + size_t len = 0; + uint8_t *buf = JS_WriteObject(ctx, &len, mod, + JS_WRITE_OBJ_BYTECODE|JS_WRITE_OBJ_REFERENCE); + assert(buf); + assert(len > 0); + JS_FreeValue(ctx, mod); + assert(loader_calls == 1); + mod = JS_ReadObject(ctx, buf, len, JS_READ_OBJ_BYTECODE); + js_free(ctx, buf); + assert(loader_calls == 1); // 'b' is returned from cache + assert(!JS_IsException(mod)); + JSValue ret = JS_EvalFunction(ctx, mod); + assert(!JS_IsException(ret)); + assert(JS_IsPromise(ret)); + JSValue result = JS_PromiseResult(ctx, ret); + assert(!JS_IsException(result)); + assert(JS_IsUndefined(result)); + JS_FreeValue(ctx, result); + JS_FreeValue(ctx, ret); + JS_FreeValue(ctx, mod); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static void runtime_cstring_free(void) +{ + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + // string -> cstring + JS_FreeCStringRT + { + JSValue ret = eval(ctx, "\"testStringPleaseIgnore\""); + assert(JS_IsString(ret)); + const char *s = JS_ToCString(ctx, ret); + assert(s); + assert(strcmp(s, "testStringPleaseIgnore") == 0); + JS_FreeCStringRT(rt, s); + JS_FreeValue(ctx, ret); + } + // string -> cstring + JS_FreeCStringRT, destroying the source value first + { + JSValue ret = eval(ctx, "\"testStringPleaseIgnore\""); + assert(JS_IsString(ret)); + const char *s = JS_ToCString(ctx, ret); + assert(s); + JS_FreeValue(ctx, ret); + assert(strcmp(s, "testStringPleaseIgnore") == 0); + JS_FreeCStringRT(rt, s); + } + // number -> cstring + JS_FreeCStringRT + { + JSValue ret = eval(ctx, "123987"); + assert(JS_IsNumber(ret)); + const char *s = JS_ToCString(ctx, ret); + assert(s); + assert(strcmp(s, "123987") == 0); + JS_FreeCStringRT(rt, s); + JS_FreeValue(ctx, ret); + } + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static void two_byte_string(void) +{ + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + { + JSValue v = JS_NewTwoByteString(ctx, NULL, 0); + assert(!JS_IsException(v)); + const char *s = JS_ToCString(ctx, v); + assert(s); + assert(!strcmp(s, "")); + JS_FreeCString(ctx, s); + JS_FreeValue(ctx, v); + } + { + JSValue v = JS_NewTwoByteString(ctx, (uint16_t[]){'o','k'}, 2); + assert(!JS_IsException(v)); + const char *s = JS_ToCString(ctx, v); + assert(s); + assert(!strcmp(s, "ok")); + JS_FreeCString(ctx, s); + JS_FreeValue(ctx, v); + } + { + JSValue v = JS_NewTwoByteString(ctx, (uint16_t[]){0xD800}, 1); + assert(!JS_IsException(v)); + const char *s = JS_ToCString(ctx, v); + assert(s); + // questionable but surrogates don't map to UTF-8 without WTF-8 + assert(!strcmp(s, "\xED\xA0\x80")); + JS_FreeCString(ctx, s); + JS_FreeValue(ctx, v); + } + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static void weak_map_gc_check(void) +{ + static const char init_code[] = +"const map = new WeakMap(); \ +function addItem() { \ + const k = { \ + text: 'a', \ + }; \ + map.set(k, {k}); \ +}"; + static const char test_code[] = "addItem()"; + + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + + JSValue ret = eval(ctx, init_code); + assert(!JS_IsException(ret)); + + JSValue ret_test = eval(ctx, test_code); + assert(!JS_IsException(ret_test)); + JS_RunGC(rt); + JSMemoryUsage memory_usage; + JS_ComputeMemoryUsage(rt, &memory_usage); + + for (int i = 0; i < 3; i++) { + JSValue ret_test2 = eval(ctx, test_code); + assert(!JS_IsException(ret_test2)); + JS_RunGC(rt); + JSMemoryUsage memory_usage2; + JS_ComputeMemoryUsage(rt, &memory_usage2); + + assert(memory_usage.memory_used_count == memory_usage2.memory_used_count); + assert(memory_usage.memory_used_size == memory_usage2.memory_used_size); + JS_FreeValue(ctx, ret_test2); + } + + JS_FreeValue(ctx, ret); + JS_FreeValue(ctx, ret_test); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +struct { + int hook_type_call_count[4]; +} promise_hook_state; + +static void promise_hook_cb(JSContext *ctx, JSPromiseHookType type, + JSValueConst promise, JSValueConst parent_promise, + void *opaque) +{ + assert(type == JS_PROMISE_HOOK_INIT || + type == JS_PROMISE_HOOK_BEFORE || + type == JS_PROMISE_HOOK_AFTER || + type == JS_PROMISE_HOOK_RESOLVE); + promise_hook_state.hook_type_call_count[type]++; + assert(opaque == (void *)&promise_hook_state); + if (!JS_IsUndefined(parent_promise)) { + JSValue global_object = JS_GetGlobalObject(ctx); + JS_SetPropertyStr(ctx, global_object, "actual", + JS_DupValue(ctx, parent_promise)); + JS_FreeValue(ctx, global_object); + } +} + +static void promise_hook(void) +{ + int *cc = promise_hook_state.hook_type_call_count; + JSContext *unused; + JSRuntime *rt = JS_NewRuntime(); + //JS_SetDumpFlags(rt, JS_DUMP_PROMISE); + JS_SetPromiseHook(rt, promise_hook_cb, &promise_hook_state); + JSContext *ctx = JS_NewContext(rt); + JSValue global_object = JS_GetGlobalObject(ctx); + { + // empty module; creates an outer and inner module promise; + // JS_Eval returns the outer promise + JSValue ret = JS_Eval(ctx, "", 0, "", JS_EVAL_TYPE_MODULE); + assert(!JS_IsException(ret)); + assert(JS_IsPromise(ret)); + assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); + JS_FreeValue(ctx, ret); + assert(2 == cc[JS_PROMISE_HOOK_INIT]); + assert(0 == cc[JS_PROMISE_HOOK_BEFORE]); + assert(0 == cc[JS_PROMISE_HOOK_AFTER]); + assert(2 == cc[JS_PROMISE_HOOK_RESOLVE]); + assert(!JS_IsJobPending(rt)); + } + memset(&promise_hook_state, 0, sizeof(promise_hook_state)); + { + // module with unresolved promise; the outer and inner module promises + // are resolved but not the user's promise + static const char code[] = "new Promise(() => {})"; + JSValue ret = JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_MODULE); + assert(!JS_IsException(ret)); + assert(JS_IsPromise(ret)); + assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise + JS_FreeValue(ctx, ret); + assert(3 == cc[JS_PROMISE_HOOK_INIT]); + assert(0 == cc[JS_PROMISE_HOOK_BEFORE]); + assert(0 == cc[JS_PROMISE_HOOK_AFTER]); + assert(2 == cc[JS_PROMISE_HOOK_RESOLVE]); // outer and inner module promise + assert(!JS_IsJobPending(rt)); + } + memset(&promise_hook_state, 0, sizeof(promise_hook_state)); + { + // module with resolved promise + static const char code[] = "new Promise((resolve,reject) => resolve())"; + JSValue ret = JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_MODULE); + assert(!JS_IsException(ret)); + assert(JS_IsPromise(ret)); + assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise + JS_FreeValue(ctx, ret); + assert(3 == cc[JS_PROMISE_HOOK_INIT]); + assert(0 == cc[JS_PROMISE_HOOK_BEFORE]); + assert(0 == cc[JS_PROMISE_HOOK_AFTER]); + assert(3 == cc[JS_PROMISE_HOOK_RESOLVE]); + assert(!JS_IsJobPending(rt)); + } + memset(&promise_hook_state, 0, sizeof(promise_hook_state)); + { + // module with rejected promise + static const char code[] = "new Promise((resolve,reject) => reject())"; + JSValue ret = JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_MODULE); + assert(!JS_IsException(ret)); + assert(JS_IsPromise(ret)); + assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise + JS_FreeValue(ctx, ret); + assert(3 == cc[JS_PROMISE_HOOK_INIT]); + assert(0 == cc[JS_PROMISE_HOOK_BEFORE]); + assert(0 == cc[JS_PROMISE_HOOK_AFTER]); + assert(2 == cc[JS_PROMISE_HOOK_RESOLVE]); + assert(!JS_IsJobPending(rt)); + } + memset(&promise_hook_state, 0, sizeof(promise_hook_state)); + { + // module with promise chain + static const char code[] = + "globalThis.count = 0;" + "globalThis.actual = undefined;" // set by promise_hook_cb + "globalThis.expected = new Promise(resolve => resolve());" + "expected.then(_ => count++)"; + JSValue ret = JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_MODULE); + assert(!JS_IsException(ret)); + assert(JS_IsPromise(ret)); + assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise + JS_FreeValue(ctx, ret); + assert(4 == cc[JS_PROMISE_HOOK_INIT]); + assert(0 == cc[JS_PROMISE_HOOK_BEFORE]); + assert(0 == cc[JS_PROMISE_HOOK_AFTER]); + assert(3 == cc[JS_PROMISE_HOOK_RESOLVE]); + JSValue v = JS_GetPropertyStr(ctx, global_object, "count"); + assert(!JS_IsException(v)); + int32_t count; + assert(0 == JS_ToInt32(ctx, &count, v)); + assert(0 == count); + JS_FreeValue(ctx, v); + assert(JS_IsJobPending(rt)); + assert(1 == JS_ExecutePendingJob(rt, &unused)); + assert(!JS_HasException(ctx)); + assert(4 == cc[JS_PROMISE_HOOK_INIT]); + assert(0 == cc[JS_PROMISE_HOOK_BEFORE]); + assert(0 == cc[JS_PROMISE_HOOK_AFTER]); + assert(4 == cc[JS_PROMISE_HOOK_RESOLVE]); + assert(!JS_IsJobPending(rt)); + v = JS_GetPropertyStr(ctx, global_object, "count"); + assert(!JS_IsException(v)); + assert(0 == JS_ToInt32(ctx, &count, v)); + assert(1 == count); + JS_FreeValue(ctx, v); + JSValue actual = JS_GetPropertyStr(ctx, global_object, "actual"); + JSValue expected = JS_GetPropertyStr(ctx, global_object, "expected"); + assert(!JS_IsException(actual)); + assert(!JS_IsException(expected)); + assert(JS_IsSameValue(ctx, actual, expected)); + JS_FreeValue(ctx, actual); + JS_FreeValue(ctx, expected); + } + memset(&promise_hook_state, 0, sizeof(promise_hook_state)); + { + // module with thenable; fires before and after hooks + static const char code[] = + "new Promise(resolve => resolve({then(resolve){ resolve() }}))"; + JSValue ret = JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_MODULE); + assert(!JS_IsException(ret)); + assert(JS_IsPromise(ret)); + assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise + JS_FreeValue(ctx, ret); + assert(3 == cc[JS_PROMISE_HOOK_INIT]); + assert(0 == cc[JS_PROMISE_HOOK_BEFORE]); + assert(0 == cc[JS_PROMISE_HOOK_AFTER]); + assert(2 == cc[JS_PROMISE_HOOK_RESOLVE]); + assert(JS_IsJobPending(rt)); + assert(1 == JS_ExecutePendingJob(rt, &unused)); + assert(!JS_HasException(ctx)); + assert(3 == cc[JS_PROMISE_HOOK_INIT]); + assert(1 == cc[JS_PROMISE_HOOK_BEFORE]); + assert(1 == cc[JS_PROMISE_HOOK_AFTER]); + assert(3 == cc[JS_PROMISE_HOOK_RESOLVE]); + assert(!JS_IsJobPending(rt)); + } + JS_FreeValue(ctx, global_object); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static void dump_memory_usage(void) +{ + JSMemoryUsage stats; + + JSRuntime *rt = NULL; + JSContext *ctx = NULL; + + rt = JS_NewRuntime(); + ctx = JS_NewContext(rt); + + //JS_SetDumpFlags(rt, JS_DUMP_PROMISE); + + static const char code[] = + "globalThis.count = 0;" + "globalThis.actual = undefined;" // set by promise_hook_cb + "globalThis.expected = new Promise(resolve => resolve());" + "expected.then(_ => count++)"; + + JSValue evalVal = JS_Eval(ctx, code, strlen(code), "", 0); + JS_FreeValue(ctx, evalVal); + + FILE *temp = tmpfile(); + assert(temp != NULL); + JS_ComputeMemoryUsage(rt, &stats); + JS_DumpMemoryUsage(temp, &stats, rt); + // JS_DumpMemoryUsage(stdout, &stats, rt); + fclose(temp); + + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static void new_errors(void) +{ + typedef struct { + const char name[16]; + JSValue (*func)(JSContext *, const char *, ...); + } Entry; + static const Entry entries[] = { + {"Error", JS_NewPlainError}, + {"InternalError", JS_NewInternalError}, + {"RangeError", JS_NewRangeError}, + {"ReferenceError", JS_NewReferenceError}, + {"SyntaxError", JS_NewSyntaxError}, + {"TypeError", JS_NewTypeError}, + }; + const Entry *e; + + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + for (e = entries; e < endof(entries); e++) { + JSValue obj = (*e->func)(ctx, "the %s", "needle"); + assert(!JS_IsException(obj)); + assert(JS_IsObject(obj)); + assert(JS_IsError(obj)); + const char *haystack = JS_ToCString(ctx, obj); + char needle[256]; + snprintf(needle, sizeof(needle), "%s: the needle", e->name); + assert(strstr(haystack, needle)); + JS_FreeCString(ctx, haystack); + JSValue stack = JS_GetPropertyStr(ctx, obj, "stack"); + assert(!JS_IsException(stack)); + assert(JS_IsString(stack)); + JS_FreeValue(ctx, stack); + JS_FreeValue(ctx, obj); + } + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static int gop_get_own_property(JSContext *ctx, JSPropertyDescriptor *desc, + JSValueConst obj, JSAtom prop) +{ + const char *name; + int found; + + found = 0; + name = JS_AtomToCString(ctx, prop); + if (!name) + return -1; + if (!strcmp(name, "answer")) { + found = 1; + *desc = (JSPropertyDescriptor){ + .value = JS_NewInt32(ctx, 42), + .flags = JS_PROP_C_W_E | JS_PROP_HAS_VALUE, + }; + } + JS_FreeCString(ctx, name); + return found; +} + +static void global_object_prototype(void) +{ + static const char code[] = "answer"; + JSValue global_object, proto, ret; + JSClassID class_id; + JSRuntime *rt; + JSContext *ctx; + int32_t answer; + int res; + + { + rt = JS_NewRuntime(); + ctx = JS_NewContext(rt); + proto = JS_NewObject(ctx); + assert(JS_IsObject(proto)); + JSCFunctionListEntry prop = JS_PROP_INT32_DEF("answer", 42, JS_PROP_C_W_E); + JS_SetPropertyFunctionList(ctx, proto, &prop, 1); + global_object = JS_GetGlobalObject(ctx); + res = JS_SetPrototype(ctx, global_object, proto); + assert(res == true); + JS_FreeValue(ctx, global_object); + JS_FreeValue(ctx, proto); + ret = eval(ctx, code); + assert(!JS_IsException(ret)); + assert(JS_IsNumber(ret)); + res = JS_ToInt32(ctx, &answer, ret); + assert(res == 0); + assert(answer == 42); + JS_FreeValue(ctx, ret); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + } + { + JSClassExoticMethods exotic = (JSClassExoticMethods){ + .get_own_property = gop_get_own_property, + }; + JSClassDef def = (JSClassDef){ + .class_name = "Global Object", + .exotic = &exotic, + }; + rt = JS_NewRuntime(); + class_id = 0; + JS_NewClassID(rt, &class_id); + res = JS_NewClass(rt, class_id, &def); + assert(res == 0); + ctx = JS_NewContext(rt); + proto = JS_NewObjectClass(ctx, class_id); + assert(JS_IsObject(proto)); + global_object = JS_GetGlobalObject(ctx); + res = JS_SetPrototype(ctx, global_object, proto); + assert(res == true); + JS_FreeValue(ctx, global_object); + JS_FreeValue(ctx, proto); + ret = eval(ctx, code); + assert(!JS_IsException(ret)); + assert(JS_IsNumber(ret)); + res = JS_ToInt32(ctx, &answer, ret); + assert(res == 0); + assert(answer == 42); + JS_FreeValue(ctx, ret); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + } +} + +// https://github.com/quickjs-ng/quickjs/issues/1178 +static void slice_string_tocstring(void) +{ + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + JSValue ret = eval(ctx, "'.'.repeat(16384).slice(1, -1)"); + assert(!JS_IsException(ret)); + assert(JS_IsString(ret)); + const char *str = JS_ToCString(ctx, ret); + assert(strlen(str) == 16382); + JS_FreeCString(ctx, str); + JS_FreeValue(ctx, ret); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +int main(void) +{ + cfunctions(); + sync_call(); + async_call(); + async_call_stack_overflow(); + raw_context_global_var(); + is_array(); + module_serde(); + runtime_cstring_free(); + two_byte_string(); + weak_map_gc_check(); + promise_hook(); + dump_memory_usage(); + new_errors(); + global_object_prototype(); + slice_string_tocstring(); + return 0; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/builtin-array-fromasync.h b/host/cred-script/vendor/rquickjs-sys/quickjs/builtin-array-fromasync.h new file mode 100644 index 0000000..19f1f07 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/builtin-array-fromasync.h @@ -0,0 +1,113 @@ +/* File generated automatically by the QuickJS-ng compiler. */ + +#include + +const uint32_t qjsc_builtin_array_fromasync_size = 826; + +const uint8_t qjsc_builtin_array_fromasync[826] = { + 0x15, 0x0d, 0x01, 0x1a, 0x61, 0x73, 0x79, 0x6e, + 0x63, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x01, 0x10, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x01, 0x12, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x4c, 0x69, 0x6b, 0x65, 0x01, 0x0a, + 0x6d, 0x61, 0x70, 0x46, 0x6e, 0x01, 0x0e, 0x74, + 0x68, 0x69, 0x73, 0x41, 0x72, 0x67, 0x01, 0x0c, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x01, 0x02, + 0x69, 0x01, 0x1a, 0x69, 0x73, 0x43, 0x6f, 0x6e, + 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72, + 0x01, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x01, 0x0c, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x01, 0x08, + 0x69, 0x74, 0x65, 0x72, 0x01, 0x1c, 0x6e, 0x6f, + 0x74, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x01, 0x08, 0x63, 0x61, + 0x6c, 0x6c, 0x0c, 0x00, 0x02, 0x00, 0xa2, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x01, + 0xa4, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x43, 0x02, + 0x01, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x01, + 0x03, 0x05, 0xaa, 0x02, 0x00, 0x01, 0x40, 0xa0, + 0x03, 0x00, 0x01, 0x40, 0xc6, 0x03, 0x00, 0x01, + 0x40, 0xcc, 0x01, 0x00, 0x01, 0x40, 0xc8, 0x03, + 0x00, 0x01, 0x40, 0x0c, 0x60, 0x02, 0x01, 0xf8, + 0x01, 0x03, 0x0e, 0x01, 0x06, 0x05, 0x00, 0x86, + 0x04, 0x11, 0xca, 0x03, 0x00, 0x01, 0x00, 0xcc, + 0x03, 0x00, 0x01, 0x00, 0xce, 0x03, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x01, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x20, 0xcc, 0x03, 0x01, 0x01, 0x20, 0xce, + 0x03, 0x01, 0x02, 0x20, 0xd0, 0x03, 0x02, 0x00, + 0x20, 0xd2, 0x03, 0x02, 0x04, 0x20, 0xd4, 0x03, + 0x02, 0x05, 0x20, 0xd6, 0x03, 0x02, 0x06, 0x20, + 0xd8, 0x03, 0x02, 0x07, 0x20, 0x64, 0x06, 0x08, + 0x20, 0x82, 0x01, 0x07, 0x09, 0x20, 0xda, 0x03, + 0x0a, 0x08, 0x30, 0x82, 0x01, 0x0d, 0x0b, 0x20, + 0xd4, 0x01, 0x0d, 0x0c, 0x20, 0x10, 0x00, 0x01, + 0x00, 0xa0, 0x03, 0x01, 0x03, 0xc6, 0x03, 0x02, + 0x03, 0xc8, 0x03, 0x04, 0x03, 0xaa, 0x02, 0x00, + 0x03, 0xcc, 0x01, 0x03, 0x03, 0x08, 0xc4, 0x0d, + 0x62, 0x02, 0x00, 0x62, 0x01, 0x00, 0x62, 0x00, + 0x00, 0xd3, 0xcb, 0xd4, 0x11, 0xf4, 0xec, 0x08, + 0x0e, 0x39, 0x46, 0x00, 0x00, 0x00, 0xdc, 0xcc, + 0xd5, 0x11, 0xf4, 0xec, 0x08, 0x0e, 0x39, 0x46, + 0x00, 0x00, 0x00, 0xdd, 0xcd, 0x62, 0x07, 0x00, + 0x62, 0x06, 0x00, 0x62, 0x05, 0x00, 0x62, 0x04, + 0x00, 0x62, 0x03, 0x00, 0xd4, 0x39, 0x46, 0x00, + 0x00, 0x00, 0xb0, 0xec, 0x16, 0xd4, 0x98, 0x04, + 0x1b, 0x00, 0x00, 0x00, 0xb0, 0xec, 0x0c, 0xdf, + 0x11, 0x04, 0xee, 0x00, 0x00, 0x00, 0x21, 0x01, + 0x00, 0x30, 0x06, 0xce, 0xb6, 0xc4, 0x04, 0xc3, + 0x0d, 0xf7, 0xc4, 0x05, 0x09, 0xc4, 0x06, 0xd3, + 0xe0, 0x48, 0xc4, 0x07, 0x63, 0x07, 0x00, 0x07, + 0xad, 0xec, 0x0f, 0x0a, 0x11, 0x64, 0x06, 0x00, + 0x0e, 0xd3, 0xe1, 0x48, 0x11, 0x64, 0x07, 0x00, + 0x0e, 0x63, 0x07, 0x00, 0x07, 0xad, 0x6a, 0xa6, + 0x00, 0x00, 0x00, 0x62, 0x08, 0x00, 0x06, 0x11, + 0xf4, 0xed, 0x0c, 0x71, 0x43, 0x32, 0x00, 0x00, + 0x00, 0xc4, 0x08, 0x0e, 0xee, 0x05, 0x0e, 0xd3, + 0xee, 0xf2, 0x63, 0x08, 0x00, 0x8e, 0x11, 0xed, + 0x03, 0x0e, 0xb6, 0x11, 0x64, 0x08, 0x00, 0x0e, + 0x63, 0x05, 0x00, 0xec, 0x0c, 0xc3, 0x0d, 0x11, + 0x63, 0x08, 0x00, 0x21, 0x01, 0x00, 0xee, 0x06, + 0xe2, 0x63, 0x08, 0x00, 0xf1, 0x11, 0x64, 0x03, + 0x00, 0x0e, 0x63, 0x04, 0x00, 0x63, 0x08, 0x00, + 0xa7, 0x6a, 0x2a, 0x01, 0x00, 0x00, 0x62, 0x09, + 0x00, 0xd3, 0x63, 0x04, 0x00, 0x48, 0xc4, 0x09, + 0x63, 0x06, 0x00, 0xec, 0x0a, 0x63, 0x09, 0x00, + 0x8c, 0x11, 0x64, 0x09, 0x00, 0x0e, 0xd4, 0xec, + 0x17, 0xd4, 0x43, 0xef, 0x00, 0x00, 0x00, 0xd5, + 0x63, 0x09, 0x00, 0x63, 0x04, 0x00, 0x24, 0x03, + 0x00, 0x8c, 0x11, 0x64, 0x09, 0x00, 0x0e, 0x5f, + 0x04, 0x00, 0x63, 0x03, 0x00, 0x63, 0x04, 0x00, + 0x92, 0x64, 0x04, 0x00, 0x0b, 0x63, 0x09, 0x00, + 0x4d, 0x41, 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3e, + 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3f, 0x00, 0x00, + 0x00, 0xf3, 0x0e, 0xee, 0x9e, 0x62, 0x0a, 0x00, + 0x63, 0x07, 0x00, 0x43, 0xef, 0x00, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0xc4, 0x0a, 0x63, 0x05, + 0x00, 0xec, 0x09, 0xc3, 0x0d, 0x11, 0x21, 0x00, + 0x00, 0xee, 0x03, 0xe2, 0xf0, 0x11, 0x64, 0x03, + 0x00, 0x0e, 0x6d, 0x8c, 0x00, 0x00, 0x00, 0x62, + 0x0c, 0x00, 0x62, 0x0b, 0x00, 0x06, 0x11, 0xf4, + 0xed, 0x13, 0x71, 0x43, 0x41, 0x00, 0x00, 0x00, + 0xc4, 0x0b, 0x43, 0x6a, 0x00, 0x00, 0x00, 0xc4, + 0x0c, 0x0e, 0xee, 0x10, 0x0e, 0x63, 0x0a, 0x00, + 0x43, 0x6b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x8c, 0xee, 0xe0, 0x63, 0x0c, 0x00, 0xed, 0x4e, + 0x63, 0x06, 0x00, 0xec, 0x0a, 0x63, 0x0b, 0x00, + 0x8c, 0x11, 0x64, 0x0b, 0x00, 0x0e, 0xd4, 0xec, + 0x17, 0xd4, 0x43, 0xef, 0x00, 0x00, 0x00, 0xd5, + 0x63, 0x0b, 0x00, 0x63, 0x04, 0x00, 0x24, 0x03, + 0x00, 0x8c, 0x11, 0x64, 0x0b, 0x00, 0x0e, 0x5f, + 0x04, 0x00, 0x63, 0x03, 0x00, 0x63, 0x04, 0x00, + 0x92, 0x64, 0x04, 0x00, 0x0b, 0x63, 0x0b, 0x00, + 0x4d, 0x41, 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3e, + 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3f, 0x00, 0x00, + 0x00, 0xf3, 0x0e, 0xee, 0x83, 0x0e, 0x06, 0x6e, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0xee, 0x1e, 0x6e, + 0x05, 0x00, 0x00, 0x00, 0x30, 0x63, 0x0a, 0x00, + 0x42, 0x06, 0x00, 0x00, 0x00, 0xec, 0x0d, 0x63, + 0x0a, 0x00, 0x43, 0x06, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x0e, 0x6f, 0x63, 0x03, 0x00, 0x63, + 0x04, 0x00, 0x44, 0x32, 0x00, 0x00, 0x00, 0x63, + 0x03, 0x00, 0x2f, 0xc1, 0x00, 0x28, 0xc1, 0x00, + 0xcf, 0x28, +}; + diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/builtin-array-fromasync.js b/host/cred-script/vendor/rquickjs-sys/quickjs/builtin-array-fromasync.js new file mode 100644 index 0000000..a07e40e --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/builtin-array-fromasync.js @@ -0,0 +1,36 @@ +;(function(Array, TypeError, asyncIterator, defineProperty, iterator) { + "use strict" // result.length=i should throw if .length is not writable + return async function fromAsync(arrayLike, mapFn=undefined, thisArg=undefined) { + if (mapFn !== undefined && typeof mapFn !== "function") throw new TypeError("not a function") + let result, i = 0, isConstructor = typeof this === "function" + let sync = false, method = arrayLike[asyncIterator] + if (method == null) sync = true, method = arrayLike[iterator] + if (method == null) { + let {length} = arrayLike + length = +length || 0 + result = isConstructor ? new this(length) : Array(length) + while (i < length) { + let value = arrayLike[i] + if (sync) value = await value + if (mapFn) value = await mapFn.call(thisArg, value, i) + defineProperty(result, i++, {value, configurable: true, writable: true}) + } + } else { + const iter = method.call(arrayLike) + result = isConstructor ? new this() : Array() + try { + for (;;) { + let {value, done} = await iter.next() + if (done) break + if (sync) value = await value + if (mapFn) value = await mapFn.call(thisArg, value, i) + defineProperty(result, i++, {value, configurable: true, writable: true}) + } + } finally { + if (iter.return) iter.return() + } + } + result.length = i + return result + } +}) diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/ctest.c b/host/cred-script/vendor/rquickjs-sys/quickjs/ctest.c new file mode 100644 index 0000000..eeb03e8 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/ctest.c @@ -0,0 +1,17 @@ +// note: file is not actually compiled, only checked for C syntax errors +#include "quickjs.h" + +int main(void) +{ + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + JS_FreeValue(ctx, JS_NAN); + JS_FreeValue(ctx, JS_UNDEFINED); + JS_FreeValue(ctx, JS_NewFloat64(ctx, 42)); + // not a legal way of using JS_MKPTR but this is here + // to have the compiler syntax-check its definition + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_UNINITIALIZED, 0)); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return 0; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/cutils.c b/host/cred-script/vendor/rquickjs-sys/quickjs/cutils.c new file mode 100644 index 0000000..7d36ddf --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/cutils.c @@ -0,0 +1,1342 @@ +/* + * C utilities + * + * Copyright (c) 2017 Fabrice Bellard + * Copyright (c) 2018 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#if !defined(_MSC_VER) +#include +#endif +#if defined(_WIN32) +#include +#include // _beginthread +#endif +#if defined(__APPLE__) +#include +#endif + +#include "cutils.h" + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif + +void js__pstrcpy(char *buf, int buf_size, const char *str) +{ + int c; + char *q = buf; + + if (buf_size <= 0) + return; + + for(;;) { + c = *str++; + if (c == 0 || q >= buf + buf_size - 1) + break; + *q++ = c; + } + *q = '\0'; +} + +/* strcat and truncate. */ +char *js__pstrcat(char *buf, int buf_size, const char *s) +{ + int len; + len = strlen(buf); + if (len < buf_size) + js__pstrcpy(buf + len, buf_size - len, s); + return buf; +} + +int js__strstart(const char *str, const char *val, const char **ptr) +{ + const char *p, *q; + p = str; + q = val; + while (*q != '\0') { + if (*p != *q) + return 0; + p++; + q++; + } + if (ptr) + *ptr = p; + return 1; +} + +int js__has_suffix(const char *str, const char *suffix) +{ + size_t len = strlen(str); + size_t slen = strlen(suffix); + return (len >= slen && !memcmp(str + len - slen, suffix, slen)); +} + +/* Dynamic buffer package */ + +static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size) +{ + if (unlikely(size == 0)) { + free(ptr); + return NULL; + } + return realloc(ptr, size); +} + +void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func) +{ + memset(s, 0, sizeof(*s)); + if (!realloc_func) + realloc_func = dbuf_default_realloc; + s->opaque = opaque; + s->realloc_func = realloc_func; +} + +void dbuf_init(DynBuf *s) +{ + dbuf_init2(s, NULL, NULL); +} + +/* return < 0 if error */ +int dbuf_realloc(DynBuf *s, size_t new_size) +{ + size_t size; + uint8_t *new_buf; + if (new_size > s->allocated_size) { + if (s->error) + return -1; + size = s->allocated_size * 3 / 2; + if (size > new_size) + new_size = size; + new_buf = s->realloc_func(s->opaque, s->buf, new_size); + if (!new_buf) { + s->error = true; + return -1; + } + s->buf = new_buf; + s->allocated_size = new_size; + } + return 0; +} + +int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len) +{ + size_t end; + end = offset + len; + if (dbuf_realloc(s, end)) + return -1; + memcpy(s->buf + offset, data, len); + if (end > s->size) + s->size = end; + return 0; +} + +int dbuf_put(DynBuf *s, const void *data, size_t len) +{ + if (unlikely((s->size + len) > s->allocated_size)) { + if (dbuf_realloc(s, s->size + len)) + return -1; + } + if (len > 0) { + memcpy(s->buf + s->size, data, len); + s->size += len; + } + return 0; +} + +int dbuf_put_self(DynBuf *s, size_t offset, size_t len) +{ + if (unlikely((s->size + len) > s->allocated_size)) { + if (dbuf_realloc(s, s->size + len)) + return -1; + } + memcpy(s->buf + s->size, s->buf + offset, len); + s->size += len; + return 0; +} + +int dbuf_putc(DynBuf *s, uint8_t c) +{ + return dbuf_put(s, &c, 1); +} + +int dbuf_putstr(DynBuf *s, const char *str) +{ + return dbuf_put(s, (const uint8_t *)str, strlen(str)); +} + +int JS_PRINTF_FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, JS_PRINTF_FORMAT const char *fmt, ...) +{ + va_list ap; + char buf[128]; + int len; + + va_start(ap, fmt); + len = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + if (len < (int)sizeof(buf)) { + /* fast case */ + return dbuf_put(s, (uint8_t *)buf, len); + } else { + if (dbuf_realloc(s, s->size + len + 1)) + return -1; + va_start(ap, fmt); + vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size, + fmt, ap); + va_end(ap); + s->size += len; + } + return 0; +} + +void dbuf_free(DynBuf *s) +{ + /* we test s->buf as a fail safe to avoid crashing if dbuf_free() + is called twice */ + if (s->buf) { + s->realloc_func(s->opaque, s->buf, 0); + } + memset(s, 0, sizeof(*s)); +} + +/*--- UTF-8 utility functions --*/ + +/* Note: only encode valid codepoints (0x0000..0x10FFFF). + At most UTF8_CHAR_LEN_MAX bytes are output. */ + +/* Compute the number of bytes of the UTF-8 encoding for a codepoint + `c` is a code-point. + Returns the number of bytes. If a codepoint is beyond 0x10FFFF the + return value is 3 as the codepoint would be encoded as 0xFFFD. + */ +size_t utf8_encode_len(uint32_t c) +{ + if (c < 0x80) + return 1; + if (c < 0x800) + return 2; + if (c < 0x10000) + return 3; + if (c < 0x110000) + return 4; + return 3; +} + +/* Encode a codepoint in UTF-8 + `buf` points to an array of at least `UTF8_CHAR_LEN_MAX` bytes + `c` is a code-point. + Returns the number of bytes. If a codepoint is beyond 0x10FFFF the + return value is 3 and the codepoint is encoded as 0xFFFD. + No null byte is stored after the encoded bytes. + Return value is in range 1..4 + */ +size_t utf8_encode(uint8_t buf[minimum_length(UTF8_CHAR_LEN_MAX)], uint32_t c) +{ + if (c < 0x80) { + buf[0] = c; + return 1; + } + if (c < 0x800) { + buf[0] = (c >> 6) | 0xC0; + buf[1] = (c & 0x3F) | 0x80; + return 2; + } + if (c < 0x10000) { + buf[0] = (c >> 12) | 0xE0; + buf[1] = ((c >> 6) & 0x3F) | 0x80; + buf[2] = (c & 0x3F) | 0x80; + return 3; + } + if (c < 0x110000) { + buf[0] = (c >> 18) | 0xF0; + buf[1] = ((c >> 12) & 0x3F) | 0x80; + buf[2] = ((c >> 6) & 0x3F) | 0x80; + buf[3] = (c & 0x3F) | 0x80; + return 4; + } + buf[0] = (0xFFFD >> 12) | 0xE0; + buf[1] = ((0xFFFD >> 6) & 0x3F) | 0x80; + buf[2] = (0xFFFD & 0x3F) | 0x80; + return 3; +} + +/* Decode a single code point from a UTF-8 encoded array of bytes + `p` is a valid pointer to an array of bytes + `pp` is a valid pointer to a `const uint8_t *` to store a pointer + to the byte following the current sequence. + Return the code point at `p`, in the range `0..0x10FFFF` + Return 0xFFFD on error. Only a single byte is consumed in this case + The maximum length for a UTF-8 byte sequence is 4 bytes. + This implements the algorithm specified in whatwg.org, except it accepts + UTF-8 encoded surrogates as JavaScript allows them in strings. + The source string is assumed to have at least UTF8_CHAR_LEN_MAX bytes + or be null terminated. + If `p[0]` is '\0', the return value is `0` and the byte is consumed. + cf: https://encoding.spec.whatwg.org/#utf-8-encoder + */ +uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp) +{ + uint32_t c; + uint8_t lower, upper; + + c = *p++; + if (c < 0x80) { + *pp = p; + return c; + } + switch(c) { + case 0xC2: case 0xC3: + case 0xC4: case 0xC5: case 0xC6: case 0xC7: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + case 0xCC: case 0xCD: case 0xCE: case 0xCF: + case 0xD0: case 0xD1: case 0xD2: case 0xD3: + case 0xD4: case 0xD5: case 0xD6: case 0xD7: + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + if (*p >= 0x80 && *p <= 0xBF) { + *pp = p + 1; + return ((c - 0xC0) << 6) + (*p - 0x80); + } + // otherwise encoding error + break; + case 0xE0: + lower = 0xA0; /* reject invalid encoding */ + goto need2; + case 0xE1: case 0xE2: case 0xE3: + case 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xE8: case 0xE9: case 0xEA: case 0xEB: + case 0xEC: case 0xED: case 0xEE: case 0xEF: + lower = 0x80; + need2: + if (*p >= lower && *p <= 0xBF && p[1] >= 0x80 && p[1] <= 0xBF) { + *pp = p + 2; + return ((c - 0xE0) << 12) + ((*p - 0x80) << 6) + (p[1] - 0x80); + } + // otherwise encoding error + break; + case 0xF0: + lower = 0x90; /* reject invalid encoding */ + upper = 0xBF; + goto need3; + case 0xF4: + lower = 0x80; + upper = 0x8F; /* reject values above 0x10FFFF */ + goto need3; + case 0xF1: case 0xF2: case 0xF3: + lower = 0x80; + upper = 0xBF; + need3: + if (*p >= lower && *p <= upper && p[1] >= 0x80 && p[1] <= 0xBF + && p[2] >= 0x80 && p[2] <= 0xBF) { + *pp = p + 3; + return ((c - 0xF0) << 18) + ((*p - 0x80) << 12) + + ((p[1] - 0x80) << 6) + (p[2] - 0x80); + } + // otherwise encoding error + break; + default: + // invalid lead byte + break; + } + *pp = p; + return 0xFFFD; +} + +uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp) { + switch (max_len) { + case 0: + *pp = p; + return 0xFFFD; + case 1: + if (*p < 0x80) + goto good; + break; + case 2: + if (*p < 0xE0) + goto good; + break; + case 3: + if (*p < 0xF0) + goto good; + break; + default: + good: + return utf8_decode(p, pp); + } + *pp = p + 1; + return 0xFFFD; +} + +/* Scan a UTF-8 encoded buffer for content type + `buf` is a valid pointer to a UTF-8 encoded string + `len` is the number of bytes to scan + `plen` points to a `size_t` variable to receive the number of units + Return value is a mask of bits. + - `UTF8_PLAIN_ASCII`: return value for 7-bit ASCII plain text + - `UTF8_NON_ASCII`: bit for non ASCII code points (8-bit or more) + - `UTF8_HAS_16BIT`: bit for 16-bit code points + - `UTF8_HAS_NON_BMP1`: bit for non-BMP1 code points, needs UTF-16 surrogate pairs + - `UTF8_HAS_ERRORS`: bit for encoding errors + */ +int utf8_scan(const char *buf, size_t buf_len, size_t *plen) +{ + const uint8_t *p, *p_end, *p_next; + size_t i, len; + int kind; + uint8_t cbits; + + kind = UTF8_PLAIN_ASCII; + cbits = 0; + len = buf_len; + // TODO: handle more than 1 byte at a time + for (i = 0; i < buf_len; i++) + cbits |= buf[i]; + if (cbits >= 0x80) { + p = (const uint8_t *)buf; + p_end = p + buf_len; + kind = UTF8_NON_ASCII; + len = 0; + while (p < p_end) { + len++; + if (*p++ >= 0x80) { + /* parse UTF-8 sequence, check for encoding error */ + uint32_t c = utf8_decode_len(p - 1, p_end - (p - 1), &p_next); + if (p_next == p) + kind |= UTF8_HAS_ERRORS; + p = p_next; + if (c > 0xFF) { + kind |= UTF8_HAS_16BIT; + if (c > 0xFFFF) { + len++; + kind |= UTF8_HAS_NON_BMP1; + } + } + } + } + } + *plen = len; + return kind; +} + +/* Decode a string encoded in UTF-8 into an array of bytes + `src` points to the source string. It is assumed to be correctly encoded + and only contains code points below 0x800 + `src_len` is the length of the source string + `dest` points to the destination array, it can be null if `dest_len` is `0` + `dest_len` is the length of the destination array. A null + terminator is stored at the end of the array unless `dest_len` is `0`. + */ +size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len) +{ + const uint8_t *p, *p_end; + size_t i; + + p = (const uint8_t *)src; + p_end = p + src_len; + for (i = 0; p < p_end; i++) { + uint32_t c = *p++; + if (c >= 0xC0) + c = (c << 6) + *p++ - ((0xC0 << 6) + 0x80); + if (i < dest_len) + dest[i] = c; + } + if (i < dest_len) + dest[i] = '\0'; + else if (dest_len > 0) + dest[dest_len - 1] = '\0'; + return i; +} + +/* Decode a string encoded in UTF-8 into an array of 16-bit words + `src` points to the source string. It is assumed to be correctly encoded. + `src_len` is the length of the source string + `dest` points to the destination array, it can be null if `dest_len` is `0` + `dest_len` is the length of the destination array. No null terminator is + stored at the end of the array. + */ +size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len) +{ + const uint8_t *p, *p_end; + size_t i; + + p = (const uint8_t *)src; + p_end = p + src_len; + for (i = 0; p < p_end; i++) { + uint32_t c = *p++; + if (c >= 0x80) { + /* parse utf-8 sequence */ + c = utf8_decode_len(p - 1, p_end - (p - 1), &p); + /* encoding errors are converted as 0xFFFD and use a single byte */ + if (c > 0xFFFF) { + if (i < dest_len) + dest[i] = get_hi_surrogate(c); + i++; + c = get_lo_surrogate(c); + } + } + if (i < dest_len) + dest[i] = c; + } + return i; +} + +/* Encode a buffer of 8-bit bytes as a UTF-8 encoded string + `src` points to the source buffer. + `src_len` is the length of the source buffer + `dest` points to the destination array, it can be null if `dest_len` is `0` + `dest_len` is the length in bytes of the destination array. A null + terminator is stored at the end of the array unless `dest_len` is `0`. + */ +size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len) +{ + size_t i, j; + uint32_t c; + + for (i = j = 0; i < src_len; i++) { + c = src[i]; + if (c < 0x80) { + if (j + 1 >= dest_len) + goto overflow; + dest[j++] = c; + } else { + if (j + 2 >= dest_len) + goto overflow; + dest[j++] = (c >> 6) | 0xC0; + dest[j++] = (c & 0x3F) | 0x80; + } + } + if (j < dest_len) + dest[j] = '\0'; + return j; + +overflow: + if (j < dest_len) + dest[j] = '\0'; + while (i < src_len) + j += 1 + (src[i++] >= 0x80); + return j; +} + +/* Encode a buffer of 16-bit code points as a UTF-8 encoded string + `src` points to the source buffer. + `src_len` is the length of the source buffer + `dest` points to the destination array, it can be null if `dest_len` is `0` + `dest_len` is the length in bytes of the destination array. A null + terminator is stored at the end of the array unless `dest_len` is `0`. + */ +size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len) +{ + size_t i, j; + uint32_t c; + + for (i = j = 0; i < src_len;) { + c = src[i++]; + if (c < 0x80) { + if (j + 1 >= dest_len) + goto overflow; + dest[j++] = c; + } else { + if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i])) + c = from_surrogate(c, src[i++]); + if (j + utf8_encode_len(c) >= dest_len) + goto overflow; + j += utf8_encode((uint8_t *)dest + j, c); + } + } + if (j < dest_len) + dest[j] = '\0'; + return j; + +overflow: + i -= 1 + (c > 0xFFFF); + if (j < dest_len) + dest[j] = '\0'; + while (i < src_len) { + c = src[i++]; + if (c < 0x80) { + j++; + } else { + if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i])) + c = from_surrogate(c, src[i++]); + j += utf8_encode_len(c); + } + } + return j; +} + +/*---- sorting with opaque argument ----*/ + +typedef void (*exchange_f)(void *a, void *b, size_t size); +typedef int (*cmp_f)(const void *, const void *, void *opaque); + +static void exchange_bytes(void *a, void *b, size_t size) { + uint8_t *ap = (uint8_t *)a; + uint8_t *bp = (uint8_t *)b; + + while (size-- != 0) { + uint8_t t = *ap; + *ap++ = *bp; + *bp++ = t; + } +} + +static void exchange_one_byte(void *a, void *b, size_t size) { + uint8_t *ap = (uint8_t *)a; + uint8_t *bp = (uint8_t *)b; + uint8_t t = *ap; + *ap = *bp; + *bp = t; +} + +static void exchange_int16s(void *a, void *b, size_t size) { + uint16_t *ap = (uint16_t *)a; + uint16_t *bp = (uint16_t *)b; + + for (size /= sizeof(uint16_t); size-- != 0;) { + uint16_t t = *ap; + *ap++ = *bp; + *bp++ = t; + } +} + +static void exchange_one_int16(void *a, void *b, size_t size) { + uint16_t *ap = (uint16_t *)a; + uint16_t *bp = (uint16_t *)b; + uint16_t t = *ap; + *ap = *bp; + *bp = t; +} + +static void exchange_int32s(void *a, void *b, size_t size) { + uint32_t *ap = (uint32_t *)a; + uint32_t *bp = (uint32_t *)b; + + for (size /= sizeof(uint32_t); size-- != 0;) { + uint32_t t = *ap; + *ap++ = *bp; + *bp++ = t; + } +} + +static void exchange_one_int32(void *a, void *b, size_t size) { + uint32_t *ap = (uint32_t *)a; + uint32_t *bp = (uint32_t *)b; + uint32_t t = *ap; + *ap = *bp; + *bp = t; +} + +static void exchange_int64s(void *a, void *b, size_t size) { + uint64_t *ap = (uint64_t *)a; + uint64_t *bp = (uint64_t *)b; + + for (size /= sizeof(uint64_t); size-- != 0;) { + uint64_t t = *ap; + *ap++ = *bp; + *bp++ = t; + } +} + +static void exchange_one_int64(void *a, void *b, size_t size) { + uint64_t *ap = (uint64_t *)a; + uint64_t *bp = (uint64_t *)b; + uint64_t t = *ap; + *ap = *bp; + *bp = t; +} + +static void exchange_int128s(void *a, void *b, size_t size) { + uint64_t *ap = (uint64_t *)a; + uint64_t *bp = (uint64_t *)b; + + for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) { + uint64_t t = ap[0]; + uint64_t u = ap[1]; + ap[0] = bp[0]; + ap[1] = bp[1]; + bp[0] = t; + bp[1] = u; + } +} + +static void exchange_one_int128(void *a, void *b, size_t size) { + uint64_t *ap = (uint64_t *)a; + uint64_t *bp = (uint64_t *)b; + uint64_t t = ap[0]; + uint64_t u = ap[1]; + ap[0] = bp[0]; + ap[1] = bp[1]; + bp[0] = t; + bp[1] = u; +} + +static inline exchange_f exchange_func(const void *base, size_t size) { + switch (((uintptr_t)base | (uintptr_t)size) & 15) { + case 0: + if (size == sizeof(uint64_t) * 2) + return exchange_one_int128; + else + return exchange_int128s; + case 8: + if (size == sizeof(uint64_t)) + return exchange_one_int64; + else + return exchange_int64s; + case 4: + case 12: + if (size == sizeof(uint32_t)) + return exchange_one_int32; + else + return exchange_int32s; + case 2: + case 6: + case 10: + case 14: + if (size == sizeof(uint16_t)) + return exchange_one_int16; + else + return exchange_int16s; + default: + if (size == 1) + return exchange_one_byte; + else + return exchange_bytes; + } +} + +static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) +{ + uint8_t *basep = (uint8_t *)base; + size_t i, n, c, r; + exchange_f swap = exchange_func(base, size); + + if (nmemb > 1) { + i = (nmemb / 2) * size; + n = nmemb * size; + + while (i > 0) { + i -= size; + for (r = i; (c = r * 2 + size) < n; r = c) { + if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0) + c += size; + if (cmp(basep + r, basep + c, opaque) > 0) + break; + swap(basep + r, basep + c, size); + } + } + for (i = n - size; i > 0; i -= size) { + swap(basep, basep + i, size); + + for (r = 0; (c = r * 2 + size) < i; r = c) { + if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0) + c += size; + if (cmp(basep + r, basep + c, opaque) > 0) + break; + swap(basep + r, basep + c, size); + } + } + } +} + +static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque) +{ + return cmp(a, b, opaque) < 0 ? + (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) : + (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c )); +} + +/* pointer based version with local stack and insertion sort threshhold */ +void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) +{ + struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack; + uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m; + size_t m4, i, lt, gt, span, span2; + int c, depth; + exchange_f swap = exchange_func(base, size); + exchange_f swap_block = exchange_func(base, size | 128); + + if (nmemb < 2 || size <= 0) + return; + + sp->base = (uint8_t *)base; + sp->count = nmemb; + sp->depth = 0; + sp++; + + while (sp > stack) { + sp--; + ptr = sp->base; + nmemb = sp->count; + depth = sp->depth; + + while (nmemb > 6) { + if (++depth > 50) { + /* depth check to ensure worst case logarithmic time */ + heapsortx(ptr, nmemb, size, cmp, opaque); + nmemb = 0; + break; + } + /* select median of 3 from 1/4, 1/2, 3/4 positions */ + /* should use median of 5 or 9? */ + m4 = (nmemb >> 2) * size; + m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque); + swap(ptr, m, size); /* move the pivot to the start or the array */ + i = lt = 1; + pi = plt = ptr + size; + gt = nmemb; + pj = pgt = top = ptr + nmemb * size; + for (;;) { + while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) { + if (c == 0) { + swap(plt, pi, size); + lt++; + plt += size; + } + i++; + pi += size; + } + while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) { + if (c == 0) { + gt--; + pgt -= size; + swap(pgt, pj, size); + } + } + if (pi >= pj) + break; + swap(pi, pj, size); + i++; + pi += size; + } + /* array has 4 parts: + * from 0 to lt excluded: elements identical to pivot + * from lt to pi excluded: elements smaller than pivot + * from pi to gt excluded: elements greater than pivot + * from gt to n excluded: elements identical to pivot + */ + /* move elements identical to pivot in the middle of the array: */ + /* swap values in ranges [0..lt[ and [i-lt..i[ + swapping the smallest span between lt and i-lt is sufficient + */ + span = plt - ptr; + span2 = pi - plt; + lt = i - lt; + if (span > span2) + span = span2; + swap_block(ptr, pi - span, span); + /* swap values in ranges [gt..top[ and [i..top-(top-gt)[ + swapping the smallest span between top-gt and gt-i is sufficient + */ + span = top - pgt; + span2 = pgt - pi; + pgt = top - span2; + gt = nmemb - (gt - i); + if (span > span2) + span = span2; + swap_block(pi, top - span, span); + + /* now array has 3 parts: + * from 0 to lt excluded: elements smaller than pivot + * from lt to gt excluded: elements identical to pivot + * from gt to n excluded: elements greater than pivot + */ + /* stack the larger segment and keep processing the smaller one + to minimize stack use for pathological distributions */ + if (lt > nmemb - gt) { + sp->base = ptr; + sp->count = lt; + sp->depth = depth; + sp++; + ptr = pgt; + nmemb -= gt; + } else { + sp->base = pgt; + sp->count = nmemb - gt; + sp->depth = depth; + sp++; + nmemb = lt; + } + } + /* Use insertion sort for small fragments */ + for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) { + for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size) + swap(pj, pj - size, size); + } + } +} + +/*---- Portable time functions ----*/ + +#ifdef _WIN32 + // From: https://stackoverflow.com/a/26085827 +static int gettimeofday_msvc(struct timeval *tp) +{ + static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t)file_time.dwLowDateTime); + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long)((time - EPOCH) / 10000000L); + tp->tv_usec = (long)(system_time.wMilliseconds * 1000); + + return 0; +} + +uint64_t js__hrtime_ns(void) { + LARGE_INTEGER counter, frequency; + double scaled_freq; + double result; + + if (!QueryPerformanceFrequency(&frequency)) + abort(); + assert(frequency.QuadPart != 0); + + if (!QueryPerformanceCounter(&counter)) + abort(); + assert(counter.QuadPart != 0); + + /* Because we have no guarantee about the order of magnitude of the + * performance counter interval, integer math could cause this computation + * to overflow. Therefore we resort to floating point math. + */ + scaled_freq = (double) frequency.QuadPart / NANOSEC; + result = (double) counter.QuadPart / scaled_freq; + return (uint64_t) result; +} +#else +uint64_t js__hrtime_ns(void) { + struct timespec t; + + if (clock_gettime(CLOCK_MONOTONIC, &t)) + abort(); + + return t.tv_sec * NANOSEC + t.tv_nsec; +} +#endif + +int64_t js__gettimeofday_us(void) { + struct timeval tv; +#ifdef _WIN32 + gettimeofday_msvc(&tv); +#else + gettimeofday(&tv, NULL); +#endif + return ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec; +} + +#if defined(_WIN32) +int js_exepath(char *buffer, size_t *size_ptr) { + int utf8_len, utf16_buffer_len, utf16_len; + WCHAR* utf16_buffer; + + if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) + return -1; + + if (*size_ptr > 32768) { + /* Windows paths can never be longer than this. */ + utf16_buffer_len = 32768; + } else { + utf16_buffer_len = (int)*size_ptr; + } + + utf16_buffer = malloc(sizeof(WCHAR) * utf16_buffer_len); + if (!utf16_buffer) + return -1; + + /* Get the path as UTF-16. */ + utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len); + if (utf16_len <= 0) + goto error; + + /* Convert to UTF-8 */ + utf8_len = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + buffer, + (int)*size_ptr, + NULL, + NULL); + if (utf8_len == 0) + goto error; + + free(utf16_buffer); + + /* utf8_len *does* include the terminating null at this point, but the + * returned size shouldn't. */ + *size_ptr = utf8_len - 1; + return 0; + +error: + free(utf16_buffer); + return -1; +} +#elif defined(__APPLE__) +int js_exepath(char *buffer, size_t *size) { + /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */ + char abspath[PATH_MAX * 2 + 1]; + char exepath[PATH_MAX + 1]; + uint32_t exepath_size; + size_t abspath_size; + + if (buffer == NULL || size == NULL || *size == 0) + return -1; + + exepath_size = sizeof(exepath); + if (_NSGetExecutablePath(exepath, &exepath_size)) + return -1; + + if (realpath(exepath, abspath) != abspath) + return -1; + + abspath_size = strlen(abspath); + if (abspath_size == 0) + return -1; + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; +} +#elif defined(__linux__) || defined(__GNU__) +int js_exepath(char *buffer, size_t *size) { + ssize_t n; + + if (buffer == NULL || size == NULL || *size == 0) + return -1; + + n = *size - 1; + if (n > 0) + n = readlink("/proc/self/exe", buffer, n); + + if (n == -1) + return n; + + buffer[n] = '\0'; + *size = n; + + return 0; +} +#else +int js_exepath(char* buffer, size_t* size_ptr) { + return -1; +} +#endif + +/*--- Cross-platform threading APIs. ----*/ + +#if JS_HAVE_THREADS +#if defined(_WIN32) +typedef void (*js__once_cb)(void); + +typedef struct { + js__once_cb callback; +} js__once_data_t; + +static int WINAPI js__once_inner(INIT_ONCE *once, void *param, void **context) { + js__once_data_t *data = param; + + data->callback(); + + return 1; +} + +void js_once(js_once_t *guard, js__once_cb callback) { + js__once_data_t data = { .callback = callback }; + InitOnceExecuteOnce(guard, js__once_inner, (void*) &data, NULL); +} + +void js_mutex_init(js_mutex_t *mutex) { + InitializeCriticalSection(mutex); +} + +void js_mutex_destroy(js_mutex_t *mutex) { + DeleteCriticalSection(mutex); +} + +void js_mutex_lock(js_mutex_t *mutex) { + EnterCriticalSection(mutex); +} + +void js_mutex_unlock(js_mutex_t *mutex) { + LeaveCriticalSection(mutex); +} + +void js_cond_init(js_cond_t *cond) { + InitializeConditionVariable(cond); +} + +void js_cond_destroy(js_cond_t *cond) { + /* nothing to do */ + (void) cond; +} + +void js_cond_signal(js_cond_t *cond) { + WakeConditionVariable(cond); +} + +void js_cond_broadcast(js_cond_t *cond) { + WakeAllConditionVariable(cond); +} + +void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) { + if (!SleepConditionVariableCS(cond, mutex, INFINITE)) + abort(); +} + +int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) { + if (SleepConditionVariableCS(cond, mutex, (DWORD)(timeout / 1e6))) + return 0; + if (GetLastError() != ERROR_TIMEOUT) + abort(); + return -1; +} + +int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg, + int flags) +{ + HANDLE h, cp; + + *thrd = INVALID_HANDLE_VALUE; + if (flags & ~JS_THREAD_CREATE_DETACHED) + return -1; + h = (HANDLE)_beginthread(start, /*stacksize*/2<<20, arg); + if (!h) + return -1; + if (flags & JS_THREAD_CREATE_DETACHED) + return 0; + // _endthread() automatically closes the handle but we want to wait on + // it so make a copy. Race-y for very short-lived threads. Can be solved + // by switching to _beginthreadex(CREATE_SUSPENDED) but means changing + // |start| from __cdecl to __stdcall. + cp = GetCurrentProcess(); + if (DuplicateHandle(cp, h, cp, thrd, 0, FALSE, DUPLICATE_SAME_ACCESS)) + return 0; + return -1; +} + +int js_thread_join(js_thread_t thrd) +{ + if (WaitForSingleObject(thrd, INFINITE)) + return -1; + CloseHandle(thrd); + return 0; +} + +#else /* !defined(_WIN32) */ + +void js_once(js_once_t *guard, void (*callback)(void)) { + if (pthread_once(guard, callback)) + abort(); +} + +void js_mutex_init(js_mutex_t *mutex) { + if (pthread_mutex_init(mutex, NULL)) + abort(); +} + +void js_mutex_destroy(js_mutex_t *mutex) { + if (pthread_mutex_destroy(mutex)) + abort(); +} + +void js_mutex_lock(js_mutex_t *mutex) { + if (pthread_mutex_lock(mutex)) + abort(); +} + +void js_mutex_unlock(js_mutex_t *mutex) { + if (pthread_mutex_unlock(mutex)) + abort(); +} + +void js_cond_init(js_cond_t *cond) { +#if defined(__APPLE__) && defined(__MACH__) + if (pthread_cond_init(cond, NULL)) + abort(); +#else + pthread_condattr_t attr; + + if (pthread_condattr_init(&attr)) + abort(); + + if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) + abort(); + + if (pthread_cond_init(cond, &attr)) + abort(); + + if (pthread_condattr_destroy(&attr)) + abort(); +#endif +} + +void js_cond_destroy(js_cond_t *cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + if (pthread_cond_destroy(cond)) + abort(); +} + +void js_cond_signal(js_cond_t *cond) { + if (pthread_cond_signal(cond)) + abort(); +} + +void js_cond_broadcast(js_cond_t *cond) { + if (pthread_cond_broadcast(cond)) + abort(); +} + +void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) { +#if defined(__APPLE__) && defined(__MACH__) + int r; + + errno = 0; + r = pthread_cond_wait(cond, mutex); + + /* Workaround for a bug in OS X at least up to 13.6 + * See https://github.com/libuv/libuv/issues/4165 + */ + if (r == EINVAL && errno == EBUSY) + return; + if (r) + abort(); +#else + if (pthread_cond_wait(cond, mutex)) + abort(); +#endif +} + +int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) { + int r; + struct timespec ts; + +#if !defined(__APPLE__) + timeout += js__hrtime_ns(); +#endif + + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; +#if defined(__APPLE__) && defined(__MACH__) + r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); +#else + r = pthread_cond_timedwait(cond, mutex, &ts); +#endif + + if (r == 0) + return 0; + + if (r == ETIMEDOUT) + return -1; + + abort(); + + /* Pacify some compilers. */ + return -1; +} + +int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg, + int flags) +{ + union { + void (*x)(void *); + void *(*f)(void *); + } u = {start}; + pthread_attr_t attr; + int ret; + + if (flags & ~JS_THREAD_CREATE_DETACHED) + return -1; + if (pthread_attr_init(&attr)) + return -1; + ret = -1; + if (pthread_attr_setstacksize(&attr, 2<<20)) + goto fail; + if (flags & JS_THREAD_CREATE_DETACHED) + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) + goto fail; + if (pthread_create(thrd, &attr, u.f, arg)) + goto fail; + ret = 0; +fail: + pthread_attr_destroy(&attr); + return ret; +} + +int js_thread_join(js_thread_t thrd) +{ + if (pthread_join(thrd, NULL)) + return -1; + return 0; +} + +#endif /* !defined(_WIN32) */ +#endif /* JS_HAVE_THREADS */ + +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/cutils.h b/host/cred-script/vendor/rquickjs-sys/quickjs/cutils.h new file mode 100644 index 0000000..f5d2a8b --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/cutils.h @@ -0,0 +1,660 @@ +/* + * C utilities + * + * Copyright (c) 2017 Fabrice Bellard + * Copyright (c) 2018 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef CUTILS_H +#define CUTILS_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) +#include +#include +#define alloca _alloca +#define ssize_t ptrdiff_t +#endif +#if defined(__APPLE__) +#include +#elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__) || defined(__GLIBC__) +#include +#elif defined(__FreeBSD__) +#include +#elif defined(_WIN32) +#include +#endif +#if !defined(_WIN32) && !defined(EMSCRIPTEN) && !defined(__wasi__) +#include +#include +#endif +#if !defined(_WIN32) +#include +#include +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +# define likely(x) (x) +# define unlikely(x) (x) +# define force_inline __forceinline +# define no_inline __declspec(noinline) +# define __maybe_unused +# define __attribute__(x) +# define __attribute(x) +#else +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +# define force_inline inline __attribute__((always_inline)) +# define no_inline __attribute__((noinline)) +# define __maybe_unused __attribute__((unused)) +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#include +#define INF INFINITY +#define NEG_INF -INFINITY +#else +#define INF (1.0/0.0) +#define NEG_INF (-1.0/0.0) +#endif + +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif +#ifndef countof +#define countof(x) (sizeof(x) / sizeof((x)[0])) +#ifndef endof +#define endof(x) ((x) + countof(x)) +#endif +#endif +#ifndef container_of +/* return the pointer of type 'type *' containing 'ptr' as field 'member' */ +#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member))) +#endif + +#if defined(_MSC_VER) || defined(__cplusplus) +#define minimum_length(n) n +#else +#define minimum_length(n) static n +#endif + +/* Borrowed from Folly */ +#ifndef JS_PRINTF_FORMAT +#ifdef _MSC_VER +#include +#define JS_PRINTF_FORMAT _Printf_format_string_ +#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) +#else +#define JS_PRINTF_FORMAT +#if !defined(__clang__) && defined(__GNUC__) +#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \ + __attribute__((format(gnu_printf, format_param, dots_param))) +#else +#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \ + __attribute__((format(printf, format_param, dots_param))) +#endif +#endif +#endif + +#if defined(PATH_MAX) +# define JS__PATH_MAX PATH_MAX +#elif defined(_WIN32) +# define JS__PATH_MAX 32767 +#else +# define JS__PATH_MAX 8192 +#endif + +void js__pstrcpy(char *buf, int buf_size, const char *str); +char *js__pstrcat(char *buf, int buf_size, const char *s); +int js__strstart(const char *str, const char *val, const char **ptr); +int js__has_suffix(const char *str, const char *suffix); + +static inline uint8_t is_be(void) { + union { + uint16_t a; + uint8_t b; + } u = { 0x100 }; + return u.b; +} + +static inline int max_int(int a, int b) +{ + if (a > b) + return a; + else + return b; +} + +static inline int min_int(int a, int b) +{ + if (a < b) + return a; + else + return b; +} + +static inline uint32_t max_uint32(uint32_t a, uint32_t b) +{ + if (a > b) + return a; + else + return b; +} + +static inline uint32_t min_uint32(uint32_t a, uint32_t b) +{ + if (a < b) + return a; + else + return b; +} + +static inline int64_t max_int64(int64_t a, int64_t b) +{ + if (a > b) + return a; + else + return b; +} + +static inline int64_t min_int64(int64_t a, int64_t b) +{ + if (a < b) + return a; + else + return b; +} + +/* WARNING: undefined if a = 0 */ +static inline int clz32(unsigned int a) +{ +#if defined(_MSC_VER) && !defined(__clang__) + unsigned long index; + _BitScanReverse(&index, a); + return 31 - index; +#else + return __builtin_clz(a); +#endif +} + +/* WARNING: undefined if a = 0 */ +static inline int clz64(uint64_t a) +{ +#if defined(_MSC_VER) && !defined(__clang__) +#if INTPTR_MAX == INT64_MAX + unsigned long index; + _BitScanReverse64(&index, a); + return 63 - index; +#else + if (a >> 32) + return clz32((unsigned)(a >> 32)); + else + return clz32((unsigned)a) + 32; +#endif +#else + return __builtin_clzll(a); +#endif +} + +/* WARNING: undefined if a = 0 */ +static inline int ctz32(unsigned int a) +{ +#if defined(_MSC_VER) && !defined(__clang__) + unsigned long index; + _BitScanForward(&index, a); + return index; +#else + return __builtin_ctz(a); +#endif +} + +/* WARNING: undefined if a = 0 */ +static inline int ctz64(uint64_t a) +{ +#if defined(_MSC_VER) && !defined(__clang__) + unsigned long index; + _BitScanForward64(&index, a); + return index; +#else + return __builtin_ctzll(a); +#endif +} + +static inline uint64_t get_u64(const uint8_t *tab) +{ + uint64_t v; + memcpy(&v, tab, sizeof(v)); + return v; +} + +static inline int64_t get_i64(const uint8_t *tab) +{ + int64_t v; + memcpy(&v, tab, sizeof(v)); + return v; +} + +static inline void put_u64(uint8_t *tab, uint64_t val) +{ + memcpy(tab, &val, sizeof(val)); +} + +static inline uint32_t get_u32(const uint8_t *tab) +{ + uint32_t v; + memcpy(&v, tab, sizeof(v)); + return v; +} + +static inline int32_t get_i32(const uint8_t *tab) +{ + int32_t v; + memcpy(&v, tab, sizeof(v)); + return v; +} + +static inline void put_u32(uint8_t *tab, uint32_t val) +{ + memcpy(tab, &val, sizeof(val)); +} + +static inline uint32_t get_u16(const uint8_t *tab) +{ + uint16_t v; + memcpy(&v, tab, sizeof(v)); + return v; +} + +static inline int32_t get_i16(const uint8_t *tab) +{ + int16_t v; + memcpy(&v, tab, sizeof(v)); + return v; +} + +static inline void put_u16(uint8_t *tab, uint16_t val) +{ + memcpy(tab, &val, sizeof(val)); +} + +static inline uint32_t get_u8(const uint8_t *tab) +{ + return *tab; +} + +static inline int32_t get_i8(const uint8_t *tab) +{ + return (int8_t)*tab; +} + +static inline void put_u8(uint8_t *tab, uint8_t val) +{ + *tab = val; +} + +#ifndef bswap16 +static inline uint16_t bswap16(uint16_t x) +{ + return (x >> 8) | (x << 8); +} +#endif + +#ifndef bswap32 +static inline uint32_t bswap32(uint32_t v) +{ + return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) | + ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24); +} +#endif + +#ifndef bswap64 +static inline uint64_t bswap64(uint64_t v) +{ + return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | + ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | + ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | + ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | + ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | + ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | + ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | + ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8)); +} +#endif + +static inline void inplace_bswap16(uint8_t *tab) { + put_u16(tab, bswap16(get_u16(tab))); +} + +static inline void inplace_bswap32(uint8_t *tab) { + put_u32(tab, bswap32(get_u32(tab))); +} + +static inline double fromfp16(uint16_t v) { + double d, s; + int e; + if ((v & 0x7C00) == 0x7C00) { + d = (v & 0x3FF) ? NAN : INFINITY; + } else { + d = (v & 0x3FF) / 1024.; + e = (v & 0x7C00) >> 10; + if (e == 0) { + e = -14; + } else { + d += 1; + e -= 15; + } + d = scalbn(d, e); + } + s = (v & 0x8000) ? -1.0 : 1.0; + return d * s; +} + +static inline uint16_t tofp16(double d) { + uint16_t f, s; + double t; + int e; + s = 0; + if (copysign(1, d) < 0) { // preserve sign when |d| is negative zero + d = -d; + s = 0x8000; + } + if (isinf(d)) + return s | 0x7C00; + if (isnan(d)) + return s | 0x7C01; + if (d == 0) + return s | 0; + d = 2 * frexp(d, &e); + e--; + if (e > 15) + return s | 0x7C00; // out of range, return +/-infinity + if (e < -25) { + d = 0; + e = 0; + } else if (e < -14) { + d = scalbn(d, e + 14); + e = 0; + } else { + d -= 1; + e += 15; + } + d *= 1024.; + f = (uint16_t)d; + t = d - f; + if (t < 0.5) + goto done; + if (t == 0.5) + if ((f & 1) == 0) + goto done; + // adjust for rounding + if (++f == 1024) { + f = 0; + if (++e == 31) + return s | 0x7C00; // out of range, return +/-infinity + } +done: + return s | (e << 10) | f; +} + +static inline int isfp16nan(uint16_t v) { + return (v & 0x7FFF) > 0x7C00; +} + +static inline int isfp16zero(uint16_t v) { + return (v & 0x7FFF) == 0; +} + +/* XXX: should take an extra argument to pass slack information to the caller */ +typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size); + +typedef struct DynBuf { + uint8_t *buf; + size_t size; + size_t allocated_size; + bool error; /* true if a memory allocation error occurred */ + DynBufReallocFunc *realloc_func; + void *opaque; /* for realloc_func */ +} DynBuf; + +void dbuf_init(DynBuf *s); +void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func); +int dbuf_realloc(DynBuf *s, size_t new_size); +int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len); +int dbuf_put(DynBuf *s, const void *data, size_t len); +int dbuf_put_self(DynBuf *s, size_t offset, size_t len); +int dbuf_putc(DynBuf *s, uint8_t c); +int dbuf_putstr(DynBuf *s, const char *str); +static inline int dbuf_put_u16(DynBuf *s, uint16_t val) +{ + return dbuf_put(s, (uint8_t *)&val, 2); +} +static inline int dbuf_put_u32(DynBuf *s, uint32_t val) +{ + return dbuf_put(s, (uint8_t *)&val, 4); +} +static inline int dbuf_put_u64(DynBuf *s, uint64_t val) +{ + return dbuf_put(s, (uint8_t *)&val, 8); +} +int JS_PRINTF_FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, JS_PRINTF_FORMAT const char *fmt, ...); +void dbuf_free(DynBuf *s); +static inline bool dbuf_error(DynBuf *s) { + return s->error; +} +static inline void dbuf_set_error(DynBuf *s) +{ + s->error = true; +} + +/*---- UTF-8 and UTF-16 handling ----*/ + +#define UTF8_CHAR_LEN_MAX 4 + +enum { + UTF8_PLAIN_ASCII = 0, // 7-bit ASCII plain text + UTF8_NON_ASCII = 1, // has non ASCII code points (8-bit or more) + UTF8_HAS_16BIT = 2, // has 16-bit code points + UTF8_HAS_NON_BMP1 = 4, // has non-BMP1 code points, needs UTF-16 surrogate pairs + UTF8_HAS_ERRORS = 8, // has encoding errors +}; +int utf8_scan(const char *buf, size_t len, size_t *plen); +size_t utf8_encode_len(uint32_t c); +size_t utf8_encode(uint8_t buf[minimum_length(UTF8_CHAR_LEN_MAX)], uint32_t c); +uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp); +uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp); +size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len); +size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len); +size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len); +size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len); + +static inline bool is_surrogate(uint32_t c) +{ + return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF +} + +static inline bool is_hi_surrogate(uint32_t c) +{ + return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF +} + +static inline bool is_lo_surrogate(uint32_t c) +{ + return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF +} + +static inline uint32_t get_hi_surrogate(uint32_t c) +{ + return (c >> 10) - (0x10000 >> 10) + 0xD800; +} + +static inline uint32_t get_lo_surrogate(uint32_t c) +{ + return (c & 0x3FF) | 0xDC00; +} + +static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo) +{ + return 65536 + 1024 * (hi & 1023) + (lo & 1023); +} + +static inline int from_hex(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else + return -1; +} + +static inline uint8_t is_upper_ascii(uint8_t c) { + return c >= 'A' && c <= 'Z'; +} + +static inline uint8_t to_upper_ascii(uint8_t c) { + return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c; +} + +void rqsort(void *base, size_t nmemb, size_t size, + int (*cmp)(const void *, const void *, void *), + void *arg); + +static inline uint64_t float64_as_uint64(double d) +{ + union { + double d; + uint64_t u64; + } u; + u.d = d; + return u.u64; +} + +static inline double uint64_as_float64(uint64_t u64) +{ + union { + double d; + uint64_t u64; + } u; + u.u64 = u64; + return u.d; +} + +int64_t js__gettimeofday_us(void); +uint64_t js__hrtime_ns(void); + +static inline size_t js__malloc_usable_size(const void *ptr) +{ +#if defined(__APPLE__) + return malloc_size(ptr); +#elif defined(_WIN32) + return _msize((void *)ptr); +#elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__GLIBC__) + return malloc_usable_size((void *)ptr); +#else + return 0; +#endif +} + +int js_exepath(char* buffer, size_t* size); + +/* Cross-platform threading APIs. */ + +#if defined(EMSCRIPTEN) || defined(__wasi__) + +#define JS_HAVE_THREADS 0 + +#else + +#define JS_HAVE_THREADS 1 + +#if defined(_WIN32) +#define JS_ONCE_INIT INIT_ONCE_STATIC_INIT +typedef INIT_ONCE js_once_t; +typedef CRITICAL_SECTION js_mutex_t; +typedef CONDITION_VARIABLE js_cond_t; +typedef HANDLE js_thread_t; +#else +#define JS_ONCE_INIT PTHREAD_ONCE_INIT +typedef pthread_once_t js_once_t; +typedef pthread_mutex_t js_mutex_t; +typedef pthread_cond_t js_cond_t; +typedef pthread_t js_thread_t; +#endif + +void js_once(js_once_t *guard, void (*callback)(void)); + +void js_mutex_init(js_mutex_t *mutex); +void js_mutex_destroy(js_mutex_t *mutex); +void js_mutex_lock(js_mutex_t *mutex); +void js_mutex_unlock(js_mutex_t *mutex); + +void js_cond_init(js_cond_t *cond); +void js_cond_destroy(js_cond_t *cond); +void js_cond_signal(js_cond_t *cond); +void js_cond_broadcast(js_cond_t *cond); +void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex); +int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout); + +enum { + JS_THREAD_CREATE_DETACHED = 1, +}; + +// creates threads with 2 MB stacks (glibc default) +int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg, + int flags); +int js_thread_join(js_thread_t thrd); + +#endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */ + +// JS requires strict rounding behavior. Turn on 64-bits double precision +// and disable x87 80-bits extended precision for intermediate floating-point +// results. 0x300 is extended precision, 0x200 is double precision. +// Note that `*&cw` in the asm constraints looks redundant but isn't. +#if defined(__i386__) && !defined(_MSC_VER) +#define JS_X87_FPCW_SAVE_AND_ADJUST(cw) \ + unsigned short cw; \ + __asm__ __volatile__("fnstcw %0" : "=m"(*&cw)); \ + do { \ + unsigned short t = 0x200 | (cw & ~0x300); \ + __asm__ __volatile__("fldcw %0" : /*empty*/ : "m"(*&t)); \ + } while (0) +#define JS_X87_FPCW_RESTORE(cw) \ + __asm__ __volatile__("fldcw %0" : /*empty*/ : "m"(*&cw)) +#else +#define JS_X87_FPCW_SAVE_AND_ADJUST(cw) +#define JS_X87_FPCW_RESTORE(cw) +#endif + +#ifdef __cplusplus +} /* extern "C" { */ +#endif + +#endif /* CUTILS_H */ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/cxxtest.cc b/host/cred-script/vendor/rquickjs-sys/quickjs/cxxtest.cc new file mode 100644 index 0000000..b615100 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/cxxtest.cc @@ -0,0 +1,2 @@ +// note: file is not actually compiled, only checked for C++ syntax errors +#include "ctest.c" diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/.gitignore b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/.gitignore new file mode 100644 index 0000000..b2d6de3 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/.gitignore @@ -0,0 +1,20 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/.nvmrc b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/.nvmrc new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/.nvmrc @@ -0,0 +1 @@ +18 diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/babel.config.js b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/babel.config.js new file mode 100644 index 0000000..e00595d --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/building.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/building.md new file mode 100644 index 0000000..0bf8774 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/building.md @@ -0,0 +1,63 @@ +--- +sidebar_position: 2 +--- + +# Building + +QuickJS uses [CMake] as its main build system, with an additional helper [Makefile]. + +:::note +Windows users will need to run the CMake commands manually. +::: + +## Getting the source + +```bash +git clone https://github.com/quickjs-ng/quickjs.git +cd quickjs +``` + +## Compiling everything + +```bash +make +``` + +This will build the `qjs` and `qjsc` executables and other test tools. Head over [here](./cli) for +instructions on how to use them. + +## Amalgamated builds + +The amalgamated build rolls individual source files into a single big file. +It's a good choice for projects that want to use QuickJS without CMake. + +Download quickjs-amalgam.zip from [Releases](https://github.com/quickjs-ng/quickjs/releases) + +To enable the std, os and bjson modules, compile quickjs-amalgam.c with +`-DQJS_BUILD_LIBC`. + +## Debug builds + +```bash +make debug +``` + +This will produce a debug build without optimizations, suitable for developers. + +## Running test262 + +```bash +make test262 +``` + +This will run the test262 suite. + +```bash +make test262-update +``` + +This will run the test262 suite and update the error / pass report, useful after +implementing a new feature that would alter the result of the test suite. + +[CMake]: https://cmake.org +[Makefile]: https://www.gnu.org/software/make/ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/cli.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/cli.md new file mode 100644 index 0000000..e5f83fe --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/cli.md @@ -0,0 +1,130 @@ +--- +sidebar_position: 4 +--- + +# The qjs and qjsc CLI tools + +## `qjs` - The QuickJS JavaScript interpreter + +The `qjs` executable runs the JavaScript interpreter. It includes a simple standard +library and REPL. + +``` +$ qjs +usage: qjs [options] [file [args]] +-h --help list options +-e --eval EXPR evaluate EXPR +-i --interactive go to interactive mode +-m --module load as ES6 module (default=autodetect) + --script load as ES6 script (default=autodetect) +-I --include file include an additional file + --std make 'std', 'os' and 'bjson' available to script +-T --trace trace memory allocation +-d --dump dump the memory usage stats +-D --dump-flags flags for dumping debug data (see DUMP_* defines) +-c --compile FILE compile the given JS file as a standalone executable +-o --out FILE output file for standalone executables + --exe select the executable to use as the base, defaults to the current one + --memory-limit n limit the memory usage to 'n' Kbytes + --stack-size n limit the stack size to 'n' Kbytes + --unhandled-rejection dump unhandled promise rejections +-q --quit just instantiate the interpreter and quit +``` + +The following dump flags are supported: + +``` +DUMP_BYTECODE_FINAL 0x01 /* dump pass 3 final byte code */ +DUMP_BYTECODE_PASS2 0x02 /* dump pass 2 code */ +DUMP_BYTECODE_PASS1 0x04 /* dump pass 1 code */ +DUMP_BYTECODE_HEX 0x10 /* dump bytecode in hex */ +DUMP_BYTECODE_PC2LINE 0x20 /* dump line number table */ +DUMP_BYTECODE_STACK 0x40 /* dump compute_stack_size */ +DUMP_BYTECODE_STEP 0x80 /* dump executed bytecode */ +DUMP_READ_OBJECT 0x100 /* dump the marshalled objects at load time */ +DUMP_FREE 0x200 /* dump every object free */ +DUMP_GC 0x400 /* dump the occurrence of the automatic GC */ +DUMP_GC_FREE 0x800 /* dump objects freed by the GC */ +DUMP_MODULE_RESOLVE 0x1000 /* dump module resolution steps */ +DUMP_PROMISE 0x2000 /* dump promise steps */ +DUMP_LEAKS 0x4000 /* dump leaked objects and strings in JS_FreeRuntime */ +DUMP_ATOM_LEAKS 0x8000 /* dump leaked atoms in JS_FreeRuntime */ +DUMP_MEM 0x10000 /* dump memory usage in JS_FreeRuntime */ +DUMP_OBJECTS 0x20000 /* dump objects in JS_FreeRuntime */ +DUMP_ATOMS 0x40000 /* dump atoms in JS_FreeRuntime */ +DUMP_SHAPES 0x80000 /* dump shapes in JS_FreeRuntime */ +``` + +### Creating standalone executables + +With the `qjs` CLI it's possible to create standalone executables that will bundle the given JavaScript file +alongside the binary. + +``` +$ qjs -c app.js -o app --exe qjs +``` + +The resulting `app` binary will have the same runtime dependencies as the `qjs` binary. This is acomplished +by compiling the target JavaScript file to bytecode and adding it a copy of the executable, with a little +trailer to help locate it. `--exe` expects the absolute path to `qjs`, e.g., `~/bin/qjs` or `$HOME/bin/qjs`. + +Rather than using the current executable, it's possible to use the `--exe` switch to create standalone +executables for other platforms. + +No JavaScript bundling is performed, the specified JS file cannot depend on other files. A bundler such +as `esbuild` can be used to generate an app bundle which can then be turned into the executable. + +``` +npx esbuild my-app/index.js \ + --bundle \ + --outfile=app.js \ + --external:qjs:* \ + --minify \ + --target=es2023 \ + --platform=neutral \ + --format=esm \ + --main-fields=main,module +``` + +## `qjsc` - The QuickJS JavaScript compiler + +The `qjsc` executable runs the JavaScript compiler, it can generate bytecode from +source files which can then be embedded in an executable, or it can generate the necessary +scaffolding to build a C application which embeds QuickJS. + +``` +$ qjsc +usage: qjsc [options] [files] + +options are: +-b output raw bytecode instead of C code +-e output main() and bytecode in a C file +-o output set the output filename +-n script_name set the script name (as used in stack traces) +-N cname set the C name of the generated data +-m compile as JavaScript module (default=autodetect) +-D module_name compile a dynamically loaded module or worker +-M module_name[,cname] add initialization code for an external C module +-p prefix set the prefix of the generated C names +-s strip the source code, specify twice to also strip debug info +-S n set the maximum stack size to 'n' bytes (default=262144) +``` + +Here is an example on how to create a standalone executable that embeds QuickJS +and the `examples/hello.js` JavaScript file: + +```bash +# Make sure you are in the QuickJS source directory. +$ cc hello.c cutils.c dtoa.c libregexp.c libunicode.c quickjs.c quickjs-libc.c -I. -o hello +``` + +The resulting binary `hello` will be in the current directory. + +```bash +$ ./hello +Hello World +``` + +:::note +See the ["Creating standalone executables"](#creating-standalone-executables) section for a simpler way. +::: diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/_category_.json b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/_category_.json new file mode 100644 index 0000000..6050477 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Developer Guide", + "position": 6, + "link": { + "type": "generated-index" + } +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/api.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/api.md new file mode 100644 index 0000000..78bec94 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/api.md @@ -0,0 +1,3 @@ +# API Reference + +WIP. diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/internals.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/internals.md new file mode 100644 index 0000000..4c9afea --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/internals.md @@ -0,0 +1,117 @@ +# Internals + +## Bytecode + +The compiler generates bytecode directly with no intermediate +representation such as a parse tree, hence it is very fast. Several +optimizations passes are done over the generated bytecode. + +A stack-based bytecode was chosen because it is simple and generates +compact code. + +For each function, the maximum stack size is computed at compile time so that +no runtime stack overflow tests are needed. + +A separate compressed line number table is maintained for the debug +information. + +Access to closure variables is optimized and is almost as fast as local +variables. + +Direct `eval` in strict mode is optimized. + +## Runtime + +### Strings + +Strings are stored either as an 8 bit or a 16 bit array of +characters. Hence random access to characters is always fast. + +The C API provides functions to convert JavaScript Strings to C UTF-8 encoded +strings. The most common case where the JavaScript string contains +only ASCII characters involves no copying. + +### Objects + +The object shapes (object prototype, property names and flags) are shared +between objects to save memory. + +Arrays with no holes (except at the end of the array) are optimized. + +TypedArray accesses are optimized. + +### Atoms + +Object property names and some strings are stored as Atoms (unique +strings) to save memory and allow fast comparison. Atoms are +represented as a 32 bit integer. Half of the atom range is reserved for +immediate integer literals from 0 to 2^31-1. + +### Numbers + +Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754 +floating point values. Most operations have fast paths for the 32-bit +integer case. + +### Garbage collection + +Reference counting is used to free objects automatically and +deterministically. A separate cycle removal pass is done when the allocated +memory becomes too large. The cycle removal algorithm only uses the +reference counts and the object content, so no explicit garbage +collection roots need to be manipulated in the C code. + +### JSValue + +It is a JavaScript value which can be a primitive type (such as +Number, String, ...) or an Object. NaN boxing is used in the 32-bit version +to store 64-bit floating point numbers. The representation is +optimized so that 32-bit integers and reference counted values can be +efficiently tested. + +In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The +rationale is that in 64-bit code memory usage is less critical. + +In both cases (32 or 64 bits), JSValue exactly fits two CPU registers, +so it can be efficiently returned by C functions. + +### Function call + +The engine is optimized so that function calls are fast. The system +stack holds the JavaScript parameters and local variables. + +### RegExp + +A specific regular expression engine was developed. It is both small +and efficient and supports all the ES2020+ features including the +Unicode properties. As the JavaScript compiler, it directly generates +bytecode without a parse tree. + +Backtracking with an explicit stack is used so that there is no +recursion on the system stack. Simple quantifiers are specifically +optimized to avoid recursions. + +Infinite recursions coming from quantifiers with empty terms are +avoided. + +The full regexp library weighs about 15 KiB (x86 code), excluding the +Unicode library. + +### Unicode + +A specific Unicode library was developed so that there is no +dependency on an external large Unicode library such as ICU. All the +Unicode tables are compressed while keeping a reasonable access +speed. + +The library supports case conversion, Unicode normalization, Unicode +script queries, Unicode general category queries and all Unicode +binary properties. + +The full Unicode library weighs about 45 KiB (x86 code). + +### BigInt + +BigInt is implemented with the [libbf](https://bellard.org/libbf) library. +It weights about 90 KiB (x86 code) and provides arbitrary precision IEEE 754 floating +point operations and transcendental functions with exact rounding. diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/intro.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/intro.md new file mode 100644 index 0000000..4d85efb --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/developer-guide/intro.md @@ -0,0 +1,113 @@ +--- +sidebar_position: 1 +--- + +# The QuickJS C API + +The C API was designed to be simple and efficient. The C API is +defined in the header `quickjs.h`. + +## Runtime and contexts + +`JSRuntime` represents a JavaScript runtime corresponding to an +object heap. Several runtimes can exist at the same time but they +cannot exchange objects. Inside a given runtime, no multi-threading is +supported. + +`JSContext` represents a JavaScript context (or Realm). Each +JSContext has its own global objects and system objects. There can be +several JSContexts per JSRuntime and they can share objects, similar +to frames of the same origin sharing JavaScript objects in a +web browser. + +## JSValue + +`JSValue` represents a JavaScript value which can be a primitive +type or an object. Reference counting is used, so it is important to +explicitly duplicate (`JS_DupValue()`, increment the reference +count) or free (`JS_FreeValue()`, decrement the reference count) +JSValues. + +## C functions + +C functions can be created with +`JS_NewCFunction()`. `JS_SetPropertyFunctionList()` is a +shortcut to easily add functions, setters and getters properties to a +given object. + +Unlike other embedded JavaScript engines, there is no implicit stack, +so C functions get their parameters as normal C parameters. As a +general rule, C functions take constant `JSValue`s as parameters +(so they don't need to free them) and return a newly allocated (=live) +`JSValue`. + +## Exceptions + +Most C functions can return a JavaScript exception. It +must be explicitly tested and handled by the C code. The specific +`JSValue` `JS_EXCEPTION` indicates that an exception +occurred. The actual exception object is stored in the +`JSContext` and can be retrieved with `JS_GetException()`. + +## Script evaluation + +Use `JS_Eval()` to evaluate a script or module source. + +If the script or module was compiled to bytecode with `qjsc`, it +can be evaluated by calling `js_std_eval_binary()`. The advantage +is that no compilation is needed so it is faster and smaller because +the compiler can be removed from the executable if no `eval` is +required. + +Note: the bytecode format is linked to a given QuickJS +version. Moreover, no security check is done before its +execution. Hence the bytecode should not be loaded from untrusted +sources. + +## JS Classes + +C opaque data can be attached to a JavaScript object. The type of the +C opaque data is determined with the class ID (`JSClassID`) of +the object. Hence the first step is to register a new class ID and JS +class (`JS_NewClassID()`, `JS_NewClass()`). Then you can +create objects of this class with `JS_NewObjectClass()` and get or +set the C opaque point with `JS_GetOpaque()` / `JS_SetOpaque()`. + +When defining a new JS class, it is possible to declare a finalizer +which is called when the object is destroyed. The finalizer should be +used to release C resources. It is invalid to execute JS code from +it. A `gc_mark` method can be provided so that the cycle removal +algorithm can find the other objects referenced by this object. Other +methods are available to define exotic object behaviors. + +The Class ID are allocated per-runtime. The +`JSClass` are allocated per `JSRuntime`. `JS_SetClassProto()` +is used to define a prototype for a given class in a given +`JSContext`. `JS_NewObjectClass()` sets this prototype in the +created object. + +Examples are available in `quickjs-libc.c`. + +## C Modules + +Native ES6 modules are supported and can be dynamically or statically +linked. The standard library `quickjs-libc.c` is a good example +of a native module. + +## Memory handling + +Use `JS_SetMemoryLimit()` to set a global memory allocation limit +to a given `JSRuntime`. + +Custom memory allocation functions can be provided with `JS_NewRuntime2()`. + +The maximum system stack size can be set with `JS_SetMaxStackSize()`. + +## Execution timeout and interrupts + +Use `JS_SetInterruptHandler()` to set a callback which is +regularly called by the engine when it is executing code. This +callback can be used to implement an execution timeout. + +It is used by the command line interpreter to implement a +`Ctrl-C` handler. diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/diff.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/diff.md new file mode 100644 index 0000000..1390e1b --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/diff.md @@ -0,0 +1,68 @@ +# Differences with bellard/quickjs + +This project aims to be a drop-in replacement for those already using QuickJS. +Minimal API changes might be necessary. + +## Community development + +NG is developed in the open, interacting with the wider community and through +these interactions many improvements have already been made, including the incorporation +of patches previously maintained in other forks. + +Each PR is reviewed, iterated on, and merged in GitHub. + +To date, NG has had over 40 distinct contributors and over 400 PRs. + +## Consistent release cadence + +As the project moves forward, a steady cadence of releases has been maintained, with an +average of a new release every 2 months. + +## Testing + +Since its inception testing has been a focus. Each PR is tested in over 50 configurations, +involving different operating systems, build types and sanitizers. + +The `test262` suite is also ran for every change. + +## Cross-platform support + +In order to better support other platforms such as Windows the build system was +changed to use [CMake]. + +In addition, Windows is treated as a first class citizen, with the addition of support +for the MSVC compiler. + +[CMake]: https://cmake.org/ + +## Performance + +While being an interpreter limits the performance in comparison with other engines which +use a JIT, several significant performance improvements have been made: + +- Opcode fusion +- Polymorphic inline caching +- Memory allocation improvements +- Improved parse speeds + +## New ECMAScript APIs + +The main focus of NG is to deliver state-of-the-art JavaScript features. Typically once they +are stable (stage 4) but sometimes even at earlier stages. Here is a non-exhaustive list +of ES features present in NG: + +- Resizable ArrayBuffer +- Float16Array +- WeakRef +- FinalizationRegistry +- Iterator Helpers +- Promise.try +- Error.isError +- Set operations + +Some non-standard but widely used APIs have also been added: + +- V8's [stack trace API](https://v8.dev/docs/stack-trace-api) + - `Error.captureStackTrace` + - `Error.prepareStackTrace` + - `Error.stackTraceLimit` diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/es_features.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/es_features.md new file mode 100644 index 0000000..d57754c --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/es_features.md @@ -0,0 +1,11 @@ +--- +sidebar_position: 7 +--- + +# ECMAScript Features + +QuickJS aims to support the latest available ECMAScript features once they hit the spec. + +Progress on _test262_ compliance can be checked [here](https://test262.fyi/#|qjs_ng). + +Due to size constraints it is unlikely QuickJS will ever support the [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) APIs. diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/installation.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/installation.md new file mode 100644 index 0000000..5df467c --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/installation.md @@ -0,0 +1,34 @@ +--- +sidebar_position: 3 +--- + +# Installation + +Installing QuickJS is simple, and we provide several ways to do so. + + +## Build from source + +If you built it from source as outlined in [building](./building) you can just run: + +```bash +make install +``` + +and it will be installed in your system. The default installation path is `/usr/local`. + + +## Using a prebuilt binary + +Each [release on GitHub] includes binaries for several systems and architectures. + + +## Using jsvu + +As of version 2.2.0 of `jsvu`, QuickJS-ng will be installed when the `quickjs` engine is requested. + +```bash +npm install jsvu -g +``` + +[release on GitHub]: https://github.com/quickjs-ng/quickjs/releases diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/intro.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/intro.md new file mode 100644 index 0000000..cb63ed5 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/intro.md @@ -0,0 +1,33 @@ +--- +slug: / +sidebar_position: 1 +sidebar_label: Welcome +--- + +# Welcome to QuickJS-NG + +QuickJS is a small and embeddable JavaScript engine. It aims to support the latest +[ECMAScript] specification. + +This project is a _fork_ of the [original QuickJS project] by Fabrice Bellard and Charlie Gordon, after it went dormant, with the intent of reigniting its development. + +This project is focused on (but not limited to): + +- Community development +- Testing +- Cross-platform support +- ES features + +You can check the differences with the original project [here.](./diff) + +:::note +This site is under construction, the entire API is not yet documented. +::: + +## Getting Started + +Head over to [building](./building) if you want to build QuickJS from source or [installation](./installation) +for installing it from prebuilt binaries. + +[ECMAScript]: https://tc39.es/ecma262/ +[original QuickJS project]: https://bellard.org/quickjs diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/projects.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/projects.md new file mode 100644 index 0000000..379b01c --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/projects.md @@ -0,0 +1,44 @@ +# Projects using NG + +Here is a list of projects currently using, supporting or migrating to QuickJS-NG. +If you want yours to be listed here, please open a PR! + +## [txiki.js](https://github.com/saghul/txiki.js) + +A tiny JavaScript runtime. + +## [radare2](https://github.com/radareorg/radare2) + +Reverse engineering framework. + +## [rquickjs](https://github.com/DelSkayn/rquickjs) + +High level Rust bindings. + +## [llrt](https://github.com/awslabs/llrt) + +Lightweight JS runtime for serverless applications. + +## [nx.js](https://github.com/TooTallNate/nx.js) + +JavaScript runtime for Nintendo Switch homebrew applications. + +## [quickjs-rusty](https://github.com/Icemic/quickjs-rusty) + +Rust wrapper focus on embedding-ready and no-pain type conversion and interoperability. + +## [GodotJS](https://github.com/godotjs/GodotJS) + +This project adds TypeScript/JavaScript support for Godot 4.x. It supports multiple javascript runtimes, including QuickJS-NG. + +## [quickjs_es_runtime](https://github.com/HiRoFa/quickjs_es_runtime) + +Rust wrapper with typescript, modules, promises, async/await and much more. + +## [Lua jsregexp](https://github.com/kmarius/jsregexp) + +JavaScript regular expressions for Lua. + +## [Edbrowse](https://edbrowse.org) + +A combination editor, web-browser, and mail client that is 100% text based. diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/stdlib.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/stdlib.md new file mode 100644 index 0000000..593a1b5 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/stdlib.md @@ -0,0 +1,577 @@ +--- +sidebar_position: 5 +--- + +# Standard library + +The standard libary is provided as part of the `qjs` executable and the `quickjs-libc.c` source file +and it's not part of the core engine. + +## Globals + +### `argv0` + +Provides the executable path. + +### `scriptArgs` + +Provides the command line arguments. The first argument is the script name. + +### `print(...args)` + +Print the arguments separated by spaces and a trailing newline. + +### `console.log(...args)` + +Same as `print()`. + +### `navigator.userAgent` + +Returns `quickjs-ng/`. + +### `gc()` + +Shorthand for `std.gc()`. + +## `qjs:bjson` module + +### `bjson.write(obj, [flags])` + +Serializes the given object into the QuickJS internal serialization format. +Returns an ArrayBuffer with the serialized data. + +Supported flags: + +- `WRITE_OBJ_BYTECODE`: allow serializing functions and modules +- `WRITE_OBJ_REFERENCE`: allow serializing object references +- `WRITE_OBJ_SAB`: allow serializing SharedArrayBuffer instances +- `WRITE_OBJ_STRIP_DEBUG`: strip debugging information when serializing +- `WRITE_OBJ_STRIP_SOURCE`: strip the source information when serializing + +### `bjson.read(buf, [pos], [len], [flags])` + +De-serialize the given ArrayBuffer (in QuickJS internal serialization format) back into a JavaScript value. + +Supported flags: + +- `READ_OBJ_BYTECODE`: allow de-serializing functions and modules +- `READ_OBJ_REFERENCE`: allow de-serializing object references +- `READ_OBJ_SAB`: allow de-serializing SharedArrayBuffer instances + +## `qjs:os` module + +The `os` module provides Operating System specific functions: + +- low level file access +- signals +- timers +- basic asynchronous I/O +- workers (threads) + +The OS functions usually return 0 if OK or an OS specific negative +error code. + +### `open(filename, flags, mode = 0o666)` + +Open a file. Return a handle or < 0 if error. + +Supported flags: + +- `O_RDONLY` +- `O_WRONLY` +- `O_RDWR` +- `O_APPEND` +- `O_CREAT` +- `O_EXCL` +- `O_TRUNC` + +POSIX open flags. + +- `O_TEXT` + +(Windows specific). Open the file in text mode. The default is binary mode. + +### `close(fd)` + +Close the file handle `fd`. + +### `seek(fd, offset, whence)` + +Seek in the file. Use `std.SEEK_*` for +`whence`. `offset` is either a number or a BigInt. If +`offset` is a BigInt, a BigInt is returned too. + +### `read(fd, buffer, offset, length)` + +Read `length` bytes from the file handle `fd` to the +ArrayBuffer `buffer` at byte position `offset`. +Return the number of read bytes or < 0 if error. + +### `write(fd, buffer, offset, length)` + +Write `length` bytes to the file handle `fd` from the +ArrayBuffer `buffer` at byte position `offset`. +Return the number of written bytes or < 0 if error. + +### `isatty(fd)` + +Return `true` is `fd` is a TTY (terminal) handle. + +### `ttyGetWinSize(fd)` + +Return the TTY size as `[width, height]` or `null` if not available. + +### `ttySetRaw(fd)` + +Set the TTY in raw mode. + +### `remove(filename)` + +Remove a file. Return 0 if OK or `-errno`. + +### `rename(oldname, newname)` + +Rename a file. Return 0 if OK or `-errno`. + +### `realpath(path)` + +Return `[str, err]` where `str` is the canonicalized absolute +pathname of `path` and `err` the error code. + +### `getcwd()` + +Return `[str, err]` where `str` is the current working directory +and `err` the error code. + +### `exePath()` + +Returns the full path of the current executable or `undefined` if not available / supported. + +### `chdir(path)` + +Change the current directory. Return 0 if OK or `-errno`. + +### `mkdir(path, mode = 0o777)` + +Create a directory at `path`. Return 0 if OK or `-errno`. + +### `stat(path)` / `lstat(path)` + +Return `[obj, err]` where `obj` is an object containing the +file status of `path`. `err` is the error code. The +following fields are defined in `obj`: `dev`, `ino`, `mode`, `nlink`, +`uid`, `gid`, `rdev`, `size`, `blocks`, `atime`, `mtime`, `ctime`. The times are +specified in milliseconds since 1970. `lstat()` is the same as +`stat()` excepts that it returns information about the link +itself. + +- `S_IFMT` +- `S_IFIFO` +- `S_IFCHR` +- `S_IFDIR` +- `S_IFBLK` +- `S_IFREG` +- `S_IFSOCK` +- `S_IFLNK` +- `S_ISGID` +- `S_ISUID` + +Constants to interpret the `mode` property returned by +`stat()`. They have the same value as in the C system header +`sys/stat.h`. + +### `utimes(path, atime, mtime)` + +Change the access and modification times of the file `path`. The +times are specified in milliseconds since 1970. Return 0 if OK or `-errno`. + +### `symlink(target, linkpath)` + +Create a link at `linkpath` containing the string `target`. Return 0 if OK or `-errno`. + +### `readlink(path)` + +Return `[str, err]` where `str` is the link target and `err` +the error code. + +### `readdir(path)` + +Return `[array, err]` where `array` is an array of strings +containing the filenames of the directory `path`. `err` is +the error code. `array` contains at least `"."` and `".."` +if successful. + +### `setReadHandler(fd, func)` + +Add a read handler to the file handle `fd`. `func` is called +each time there is data pending for `fd`. A single read handler +per file handle is supported. Use `func = null` to remove the +handler. + +### `setWriteHandler(fd, func)` + +Add a write handler to the file handle `fd`. `func` is +called each time data can be written to `fd`. A single write +handler per file handle is supported. Use `func = null` to remove +the handler. + +### `signal(signal, func)` + +Call the function `func` when the signal `signal` +happens. Only a single handler per signal number is supported. Use +`null` to set the default handler or `undefined` to ignore +the signal. Signal handlers can only be defined in the main thread. + +- `SIGINT` +- `SIGABRT` +- `SIGFPE` +- `SIGILL` +- `SIGSEGV` +- `SIGTERM` + +POSIX signal numbers. + +### `kill(pid, sig)` + +Send the signal `sig` to the process `pid`. + +### `exec(args[, options])` + +Execute a process with the arguments `args`. `options` is an +object containing optional parameters: + +- `block` - Boolean (default = true). If true, wait until the process is + terminated. In this case, `exec` return the exit code if positive + or the negated signal number if the process was interrupted by a + signal. If false, do not block and return the process id of the child. +- `usePath` - Boolean (default = true). If true, the file is searched in the + `PATH` environment variable. +- `file` - String (default = `args[0]`). Set the file to be executed. +- `cwd` - String. If present, set the working directory of the new process. +- `stdin`, `stdout`, `stderr` - If present, set the handle in the child for stdin, stdout or stderr. +- `env` - Object. If present, set the process environment from the object + key-value pairs. Otherwise use the same environment as the current + process. +- `uid` - Integer. If present, the process uid with `setuid`. +- `gid` - Integer. If present, the process gid with `setgid`. +- `groups` - Array of integer. If present, the supplementary + group IDs with `setgroup`. + +### `waitpid(pid, options)` + +`waitpid` Unix system call. Return the array `[ret, status]`. +`ret` contains `-errno` in case of error. + +- `WNOHANG` + +Constant for the `options` argument of `waitpid`. + +### `dup(fd)` + +`dup` Unix system call. + +### `dup2(oldfd, newfd)` + +`dup2` Unix system call. + +### `pipe()` + +`pipe` Unix system call. Return two handles as `[read_fd, write_fd]` or null in case of error. + +### `sleep(delay_ms)` + +Sleep during `delay_ms` milliseconds. + +### `sleepAsync(delay_ms)` + +Asynchronouse sleep during `delay_ms` milliseconds. Returns a promise. Example: + +```js +await os.sleepAsync(500); +``` + +### `setTimeout(func, delay)` + +Call the function `func` after `delay` ms. Return a timer ID. + +### `clearTimeout(id)` + +Cancel a timer. + +### `platform` + +Return a string representing the platform: `"linux"`, `"darwin"`, `"win32"` or `"js"`. + +### `Worker(module_filename)` + +Constructor to create a new thread (worker) with an API close to that of +`WebWorkers`. `module_filename` is a string specifying the +module filename which is executed in the newly created thread. As for +dynamically imported module, it is relative to the current script or +module path. Threads normally don't share any data and communicate +between each other with messages. Nested workers are not supported. An +example is available in `tests/test_worker.js`. + +The worker class has the following static properties: + +- `parent` - In the created worker, `Worker.parent` represents the parent + worker and is used to send or receive messages. + +The worker instances have the following properties: + +- `postMessage(msg)` - Send a message to the corresponding worker. `msg` is cloned in + the destination worker using an algorithm similar to the `HTML` + structured clone algorithm. `SharedArrayBuffer` are shared + between workers. + +- `onmessage` - Getter and setter. Set a function which is called each time a + message is received. The function is called with a single + argument. It is an object with a `data` property containing the + received message. The thread is not terminated if there is at least + one non `null` `onmessage` handler. + +## `qjs:std` module + +The `std` module provides wrappers to libc (`stdlib.h` and `stdio.h`) and a few other utilities. + +### `exit(n)` + +Exit the process. + +### `evalScript(str, options = undefined)` + +Evaluate the string `str` as a script (global +eval). `options` is an optional object containing the following +optional properties: + +- `backtrace_barrier` - Boolean (default = false). If true, error backtraces do not list the + stack frames below the evalScript. +- `async` - Boolean (default = false). If true, `await` is accepted in the + script and a promise is returned. The promise is resolved with an + object whose `value` property holds the value returned by the + script. + +### `loadScript(filename)` + +Evaluate the file `filename` as a script (global eval). + +### `loadFile(filename, [options])` + +Load the file `filename` and return it as a string assuming UTF-8 +encoding. Return `null` in case of I/O error. + +If `options.binary` is set to `true` a `Uint8Array` is returned instead. + +### `writeFile(filename, data)` + +Create the file `filename` and write `data` into it. + +`data` can be a string, a typed array or an `ArrayBuffer`. `undefined` is +treated as the empty string. + +When `data` is a string, the file is opened in text mode; otherwise it is +opened in binary mode. (This distinction is only relevant on Windows.) + +Throws an exception if the file cannot be created or written to. + +### `open(filename, flags, errorObj = undefined)` + +Open a file (wrapper to the libc `fopen()`). Return the FILE +object or `null` in case of I/O error. If `errorObj` is not +undefined, set its `errno` property to the error code or to 0 if +no error occurred. + +### `popen(command, flags, errorObj = undefined)` + +Open a process by creating a pipe (wrapper to the libc +`popen()`). Return the FILE +object or `null` in case of I/O error. If `errorObj` is not +undefined, set its `errno` property to the error code or to 0 if +no error occurred. + +### `fdopen(fd, flags, errorObj = undefined)` + +Open a file from a file handle (wrapper to the libc +`fdopen()`). Return the FILE +object or null` in case of I/O error. If `errorObj` is not +undefined, set its `errno` property to the error code or to 0 if +no error occurred. + +### `tmpfile(errorObj = undefined)` + +Open a temporary file. Return the FILE +object or `null` in case of I/O error. If `errorObj` is not +undefined, set its `errno` property to the error code or to 0 if +no error occurred. + +### `puts(str)` + +Equivalent to `std.out.puts(str)`. + +### `printf(fmt, ...args)` + +Equivalent to `std.out.printf(fmt, ...args)`. + +### `sprintf(fmt, ...args)` + +Equivalent to the libc sprintf(). + +### `in`, `out`, `err` + +Wrappers to the libc file `stdin`, `stdout`, `stderr`. + +### `Error` + +Enumeration object containing the integer value of common errors +(additional error codes may be defined): + +- `EINVAL` +- `EIO` +- `EACCES` +- `EEXIST` +- `ENOSPC` +- `ENOSYS` +- `EBUSY` +- `ENOENT` +- `EPERM` +- `EPIPE` + +### `strerror(errno)` + +Return a string that describes the error `errno`. + +### `gc()` + +Manually invoke the cycle removal algorithm. The cycle removal +algorithm is automatically started when needed, so this function is +useful in case of specific memory constraints or for testing. + +### `getenv(name)` + +Return the value of the environment variable `name` or +`undefined` if it is not defined. + +### `setenv(name, value)` + +Set the value of the environment variable `name` to the string +`value`. + +### `unsetenv(name)` + +Delete the environment variable `name`. + +### `getenviron()` + +Return an object containing the environment variables as key-value pairs. + +### `urlGet(url, options = undefined)` + +Download `url` using the `curl` command line +utility. `options` is an optional object containing the following +optional properties: + +- `binary` - Boolean (default = false). If true, the response is an ArrayBuffer + instead of a string. When a string is returned, the data is assumed + to be UTF-8 encoded. +- `full` - Boolean (default = false). If true, return the an object contains + the properties `response` (response content), + `responseHeaders` (headers separated by CRLF), `status` + (status code). `response` is `null` is case of protocol or + network error. If `full` is false, only the response is + returned if the status is between 200 and 299. Otherwise `null` + is returned. + +### `FILE` + +File object. + +#### `close()` + +Close the file. Return 0 if OK or `-errno` in case of I/O error. + +#### `puts(str)` + +Outputs the string with the UTF-8 encoding. + +#### `printf(fmt, ...args)` + +Formatted printf. + +The same formats as the standard C library `printf` are +supported. Integer format types (e.g. `%d`) truncate the Numbers +or BigInts to 32 bits. Use the `l` modifier (e.g. `%ld`) to +truncate to 64 bits. + +#### `flush()` + +Flush the buffered file. + +#### `seek(offset, whence)` + +Seek to a give file position (whence is +`std.SEEK_*`). `offset` can be a number or a BigInt. Return +0 if OK or `-errno` in case of I/O error. + +- `SEEK_SET` +- `SEEK_CUR` +- `SEEK_END` + +Constants for seek(). + +#### `tell()` + +Return the current file position. + +#### `tello()` + +Return the current file position as a BigInt. + +#### `eof()` + +Return true if end of file. + +#### `fileno()` + +Return the associated OS handle. + +#### `error()` + +Return true if there was an error. + +#### `clearerr()` + +Clear the error indication. + +#### `read(buffer, position, length)` + +Read `length` bytes from the file to the ArrayBuffer `buffer` at byte +position `position` (wrapper to the libc `fread`). + +#### `write(buffer, position, length)` + +Write `length` bytes to the file from the ArrayBuffer `buffer` at byte +position `position` (wrapper to the libc `fwrite`). + +#### `getline()` + +Return the next line from the file, assuming UTF-8 encoding, excluding +the trailing line feed. + +#### `readAsArrayBuffer(max_size = undefined)` + +Read `max_size` bytes from the file and return them as an ArrayBuffer. +If `max_size` is not present, the file is read until its end. + +#### `readAsString(max_size = undefined)` + +Read `max_size` bytes from the file and return them as a string +assuming UTF-8 encoding. If `max_size` is not present, the file +is read until its end. + +#### `getByte()` + +Return the next byte from the file. Return -1 if the end of file is reached. + +#### `putByte(c)` + +Write one byte to the file. diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/supported_platforms.md b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/supported_platforms.md new file mode 100644 index 0000000..bb817b3 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docs/supported_platforms.md @@ -0,0 +1,20 @@ +--- +sidebar_position: 8 +--- + +# Supported Platforms + +| System | Supported versions | Notes | +|---|---|---| +| GNU/Linux | * | glibc and musl are supported | +| macOS | macOS >= 11 | Currently supported macOS releases | +| Windows | >= Windows 7* | VS >= 2022 and Clang are supported; requires `` | +| FreeBSD | * | Limited testing | +| OpenBSD | * | Limited testing | +| NetBSD | * | Limited testing | +| Android | NDK >= 26.0.10792818 | Limited testing | +| iOS | * | Limited testing | +| MinGW | MinGW-w64 | | +| Other | N/A | Missing? Open a PR! | + +- `*`: Windows 7 is EOL and only supported in this project as long as it doesn't interfere with its progress. diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docusaurus.config.js b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docusaurus.config.js new file mode 100644 index 0000000..25524ed --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/docusaurus.config.js @@ -0,0 +1,114 @@ +// @ts-check +// `@type` JSDoc annotations allow editor autocompletion and type checking +// (when paired with `@ts-check`). +// There are various equivalent ways to declare your Docusaurus config. +// See: https://docusaurus.io/docs/api/docusaurus-config + +/** @type {import('@docusaurus/types').Config} */ +const config = { + title: 'QuickJS-NG', + tagline: 'QuickJS, the Next Generation: a mighty JavaScript engine', + favicon: 'img/favicon.ico', + + // Set the production url of your site here + url: 'https://quickjs-ng.github.io', + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: '/quickjs/', + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: 'quickjs-ng', // Usually your GitHub org/user name. + projectName: 'quickjs', // Usually your repo name. + + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'throw', + + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + presets: [ + [ + 'classic', + /** @type {import('@docusaurus/preset-classic').Options} */ + ({ + docs: { + routeBasePath: '/', + sidebarPath: './sidebars.js', + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: 'https://github.com/quickjs-ng/quickjs/tree/master/docs/', + }, + blog: false, + theme: { + customCss: './src/css/custom.css', + }, + }), + ], + ], + + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + ({ + // Replace with your project's social card + image: 'img/docusaurus-social-card.jpg', + navbar: { + title: 'QuickJS-NG', + items: [ + { + type: 'docSidebar', + sidebarId: 'docsSidebar', + position: 'left', + label: 'Documentation', + }, + { + href: 'https://github.com/quickjs-ng/quickjs', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + ], + }, + { + title: 'Community', + items: [ + { + label: 'GitHub Discussions', + href: 'https://github.com/quickjs-ng/quickjs/discussions', + }, + { + label: 'Matrix', + href: 'https://matrix.to/#/%23quickjs-ng%3Amatrix.org?via=matrix.org', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'GitHub', + href: 'https://github.com/quickjs-ng/quickjs', + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} QuickJS-NG project contributors.`, + }, + prism: { + }, + }), +}; + +export default config; diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/package-lock.json b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/package-lock.json new file mode 100644 index 0000000..f13c2d8 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/package-lock.json @@ -0,0 +1,14656 @@ +{ + "name": "docs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/preset-classic": "3.5.2", + "@mdx-js/react": "3.0.1", + "clsx": "2.1.1", + "prism-react-renderer": "2.4.0", + "react": "18.3.1", + "react-dom": "18.3.1" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "3.5.2", + "@docusaurus/types": "3.5.2" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", + "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", + "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", + "dependencies": { + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", + "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", + "dependencies": { + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", + "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/cache-browser-local-storage": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz", + "integrity": "sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==", + "dependencies": { + "@algolia/cache-common": "4.24.0" + } + }, + "node_modules/@algolia/cache-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.24.0.tgz", + "integrity": "sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==" + }, + "node_modules/@algolia/cache-in-memory": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz", + "integrity": "sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==", + "dependencies": { + "@algolia/cache-common": "4.24.0" + } + }, + "node_modules/@algolia/client-account": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.24.0.tgz", + "integrity": "sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-account/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-account/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.24.0.tgz", + "integrity": "sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-analytics/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-analytics/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.5.3.tgz", + "integrity": "sha512-3rdSdreBL2LGYu4DWmUGlMhaGy1vy36Xp42LdbTFsW/y3bhW5viptMHI5A3PKT0hPEMZUn+te1iM/EWvLUuVGQ==", + "peer": true, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.24.0.tgz", + "integrity": "sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-personalization/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.5.3.tgz", + "integrity": "sha512-qrokD+uoNxchbiF9aP8niQd/9SZ6BgYg4WaesFaubHhr9DFvwGm4IePEMha8vQcc3fSsY6uL+gOtKB3J6RF0NQ==", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.5.3", + "@algolia/requester-browser-xhr": "5.5.3", + "@algolia/requester-fetch": "5.5.3", + "@algolia/requester-node-http": "5.5.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" + }, + "node_modules/@algolia/logger-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.24.0.tgz", + "integrity": "sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==" + }, + "node_modules/@algolia/logger-console": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.24.0.tgz", + "integrity": "sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==", + "dependencies": { + "@algolia/logger-common": "4.24.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.24.0.tgz", + "integrity": "sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.24.0", + "@algolia/cache-common": "4.24.0", + "@algolia/cache-in-memory": "4.24.0", + "@algolia/client-common": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/logger-common": "4.24.0", + "@algolia/logger-console": "4.24.0", + "@algolia/requester-browser-xhr": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/requester-node-http": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/requester-browser-xhr": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", + "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/requester-node-http": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", + "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.5.3.tgz", + "integrity": "sha512-LsfUPokiXEpvlYF7SwNjyyjkUX7IoW7oIhH6WkDUD4PCfEZkFbVplGQA0UrCiWOAbpb25P7mmP6+ldwjwqW6Kg==", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.5.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.24.0.tgz", + "integrity": "sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==" + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.5.3.tgz", + "integrity": "sha512-RKaliEFHtVeD/fMxwrApkcI6ZxR+mU6pZna29r3NwVMpCXTJWWtlMpQmbr1RHzUsaAlpfv9pfGJN4nYPE8XWEg==", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.5.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.5.3.tgz", + "integrity": "sha512-2wU+HlTVrVce7BMW2b3Gd62btk8B0jBbuKYYzu3OFeBD/aZa88eHABtjcjQCdw3x+wvkIPEc56UsZx9eHYLebg==", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.5.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/transporter": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.24.0.tgz", + "integrity": "sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==", + "dependencies": { + "@algolia/cache-common": "4.24.0", + "@algolia/logger-common": "4.24.0", + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "dependencies": { + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.4", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "dependencies": { + "@babel/types": "^7.25.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz", + "integrity": "sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", + "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.1.tgz", + "integrity": "sha512-SLV/giH/V4SmloZ6Dt40HjTGTAIkxn33TVIHxNGNvo8ezMhrxBkzisj4op1KZYPIOHFLqhv60OHvX+YRu4xbmQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", + "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.2.tgz", + "integrity": "sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", + "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", + "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.4.tgz", + "integrity": "sha512-8hsyG+KUYGY0coX6KUCDancA0Vw225KJ2HJO0yCNr1vq5r+lJTleDaJf0K7iOhjw4SWhu03TMBzYTJ9krmzULQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz", + "integrity": "sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", + "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", + "dependencies": { + "@babel/compat-data": "^7.25.4", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.25.4", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", + "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.24.7", + "@babel/plugin-transform-react-jsx-development": "^7.24.7", + "@babel/plugin-transform-react-pure-annotations": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", + "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "node_modules/@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.25.6.tgz", + "integrity": "sha512-Gz0Nrobx8szge6kQQ5Z5MX9L3ObqNwCQY1PSwSNzreFL7aHGxv8Fp2j3ETV6/wWdbiV+mW6OSm8oQhg3Tcsniw==", + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.6.1.tgz", + "integrity": "sha512-VtVb5DS+0hRIprU2CO6ZQjK2Zg4QU5HrDM1+ix6rT0umsYvFvatMAnf97NHZlVWDaaLlx7GRfR/7FikANiM2Fg==" + }, + "node_modules/@docsearch/react": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.6.1.tgz", + "integrity": "sha512-qXZkEPvybVhSXj0K7U3bXc233tk5e8PfhoZ6MhPOiik/qUQxYC+Dn9DnoS7CxHQQhHfCvTiN0eY9M12oRghEXw==", + "dependencies": { + "@algolia/autocomplete-core": "1.9.3", + "@algolia/autocomplete-preset-algolia": "1.9.3", + "@docsearch/css": "3.6.1", + "algoliasearch": "^4.19.1" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.5.2.tgz", + "integrity": "sha512-4Z1WkhCSkX4KO0Fw5m/Vuc7Q3NxBG53NE5u59Rs96fWkMPZVSrzEPP16/Nk6cWb/shK7xXPndTmalJtw7twL/w==", + "dependencies": { + "@babel/core": "^7.23.3", + "@babel/generator": "^7.23.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/preset-react": "^7.22.5", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", + "@babel/runtime-corejs3": "^7.22.6", + "@babel/traverse": "^7.22.8", + "@docusaurus/cssnano-preset": "3.5.2", + "@docusaurus/logger": "3.5.2", + "@docusaurus/mdx-loader": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-common": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "autoprefixer": "^10.4.14", + "babel-loader": "^9.1.3", + "babel-plugin-dynamic-import-node": "^2.3.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "clean-css": "^5.3.2", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "copy-webpack-plugin": "^11.0.0", + "core-js": "^3.31.1", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^5.0.1", + "cssnano": "^6.1.2", + "del": "^6.1.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "html-minifier-terser": "^7.2.0", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.5.3", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.7.6", + "p-map": "^4.0.0", + "postcss": "^8.4.26", + "postcss-loader": "^7.3.3", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "rtl-detect": "^1.0.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.5", + "shelljs": "^0.8.5", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "url-loader": "^4.1.1", + "webpack": "^5.88.1", + "webpack-bundle-analyzer": "^4.9.0", + "webpack-dev-server": "^4.15.1", + "webpack-merge": "^5.9.0", + "webpackbar": "^5.0.2" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@mdx-js/react": "^3.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/cssnano-preset": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.5.2.tgz", + "integrity": "sha512-D3KiQXOMA8+O0tqORBrTOEQyQxNIfPm9jEaJoALjjSjc2M/ZAWcUfPQEnwr2JB2TadHw2gqWgpZckQmrVWkytA==", + "dependencies": { + "cssnano-preset-advanced": "^6.1.2", + "postcss": "^8.4.38", + "postcss-sort-media-queries": "^5.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/logger": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.5.2.tgz", + "integrity": "sha512-LHC540SGkeLfyT3RHK3gAMK6aS5TRqOD4R72BEU/DE2M/TY8WwEUAMY576UUc/oNJXv8pGhBmQB6N9p3pt8LQw==", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/mdx-loader": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.5.2.tgz", + "integrity": "sha512-ku3xO9vZdwpiMIVd8BzWV0DCqGEbCP5zs1iHfKX50vw6jX8vQo0ylYo1YJMZyz6e+JFJ17HYHT5FzVidz2IflA==", + "dependencies": { + "@docusaurus/logger": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.5.2.tgz", + "integrity": "sha512-Z+Xu3+2rvKef/YKTMxZHsEXp1y92ac0ngjDiExRdqGTmEKtCUpkbNYH8v5eXo5Ls+dnW88n6WTa+Q54kLOkwPg==", + "dependencies": { + "@docusaurus/types": "3.5.2", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-content-blog": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.5.2.tgz", + "integrity": "sha512-R7ghWnMvjSf+aeNDH0K4fjyQnt5L0KzUEnUhmf1e3jZrv3wogeytZNN6n7X8yHcMsuZHPOrctQhXWnmxu+IRRg==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/logger": "3.5.2", + "@docusaurus/mdx-loader": "3.5.2", + "@docusaurus/theme-common": "3.5.2", + "@docusaurus/types": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-common": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "cheerio": "1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "reading-time": "^1.5.0", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.5.2.tgz", + "integrity": "sha512-Bt+OXn/CPtVqM3Di44vHjE7rPCEsRCB/DMo2qoOuozB9f7+lsdrHvD0QCHdBs0uhz6deYJDppAr2VgqybKPlVQ==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/logger": "3.5.2", + "@docusaurus/mdx-loader": "3.5.2", + "@docusaurus/module-type-aliases": "3.5.2", + "@docusaurus/theme-common": "3.5.2", + "@docusaurus/types": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-common": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "@types/react-router-config": "^5.0.7", + "combine-promises": "^1.1.0", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.5.2.tgz", + "integrity": "sha512-WzhHjNpoQAUz/ueO10cnundRz+VUtkjFhhaQ9jApyv1a46FPURO4cef89pyNIOMny1fjDz/NUN2z6Yi+5WUrCw==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/mdx-loader": "3.5.2", + "@docusaurus/types": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-debug": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.5.2.tgz", + "integrity": "sha512-kBK6GlN0itCkrmHuCS6aX1wmoWc5wpd5KJlqQ1FyrF0cLDnvsYSnh7+ftdwzt7G6lGBho8lrVwkkL9/iQvaSOA==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/types": "3.5.2", + "@docusaurus/utils": "3.5.2", + "fs-extra": "^11.1.1", + "react-json-view-lite": "^1.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.5.2.tgz", + "integrity": "sha512-rjEkJH/tJ8OXRE9bwhV2mb/WP93V441rD6XnM6MIluu7rk8qg38iSxS43ga2V2Q/2ib53PcqbDEJDG/yWQRJhQ==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/types": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.5.2.tgz", + "integrity": "sha512-lm8XL3xLkTPHFKKjLjEEAHUrW0SZBSHBE1I+i/tmYMBsjCcUB5UJ52geS5PSiOCFVR74tbPGcPHEV/gaaxFeSA==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/types": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "@types/gtag.js": "^0.0.12", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.5.2.tgz", + "integrity": "sha512-QkpX68PMOMu10Mvgvr5CfZAzZQFx8WLlOiUQ/Qmmcl6mjGK6H21WLT5x7xDmcpCoKA/3CegsqIqBR+nA137lQg==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/types": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.5.2.tgz", + "integrity": "sha512-DnlqYyRAdQ4NHY28TfHuVk414ft2uruP4QWCH//jzpHjqvKyXjj2fmDtI8RPUBh9K8iZKFMHRnLtzJKySPWvFA==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/logger": "3.5.2", + "@docusaurus/types": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-common": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "fs-extra": "^11.1.1", + "sitemap": "^7.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.5.2.tgz", + "integrity": "sha512-3ihfXQ95aOHiLB5uCu+9PRy2gZCeSZoDcqpnDvf3B+sTrMvMTr8qRUzBvWkoIqc82yG5prCboRjk1SVILKx6sg==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/plugin-content-blog": "3.5.2", + "@docusaurus/plugin-content-docs": "3.5.2", + "@docusaurus/plugin-content-pages": "3.5.2", + "@docusaurus/plugin-debug": "3.5.2", + "@docusaurus/plugin-google-analytics": "3.5.2", + "@docusaurus/plugin-google-gtag": "3.5.2", + "@docusaurus/plugin-google-tag-manager": "3.5.2", + "@docusaurus/plugin-sitemap": "3.5.2", + "@docusaurus/theme-classic": "3.5.2", + "@docusaurus/theme-common": "3.5.2", + "@docusaurus/theme-search-algolia": "3.5.2", + "@docusaurus/types": "3.5.2" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.5.2.tgz", + "integrity": "sha512-XRpinSix3NBv95Rk7xeMF9k4safMkwnpSgThn0UNQNumKvmcIYjfkwfh2BhwYh/BxMXQHJ/PdmNh22TQFpIaYg==", + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/mdx-loader": "3.5.2", + "@docusaurus/module-type-aliases": "3.5.2", + "@docusaurus/plugin-content-blog": "3.5.2", + "@docusaurus/plugin-content-docs": "3.5.2", + "@docusaurus/plugin-content-pages": "3.5.2", + "@docusaurus/theme-common": "3.5.2", + "@docusaurus/theme-translations": "3.5.2", + "@docusaurus/types": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-common": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "copy-text-to-clipboard": "^3.2.0", + "infima": "0.2.0-alpha.44", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.26", + "prism-react-renderer": "^2.3.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.5.2.tgz", + "integrity": "sha512-QXqlm9S6x9Ibwjs7I2yEDgsCocp708DrCrgHgKwg2n2AY0YQ6IjU0gAK35lHRLOvAoJUfCKpQAwUykB0R7+Eew==", + "dependencies": { + "@docusaurus/mdx-loader": "3.5.2", + "@docusaurus/module-type-aliases": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-common": "3.5.2", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^2.0.0", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.3.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-search-algolia": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.5.2.tgz", + "integrity": "sha512-qW53kp3VzMnEqZGjakaV90sst3iN1o32PH+nawv1uepROO8aEGxptcq2R5rsv7aBShSRbZwIobdvSYKsZ5pqvA==", + "dependencies": { + "@docsearch/react": "^3.5.2", + "@docusaurus/core": "3.5.2", + "@docusaurus/logger": "3.5.2", + "@docusaurus/plugin-content-docs": "3.5.2", + "@docusaurus/theme-common": "3.5.2", + "@docusaurus/theme-translations": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-validation": "3.5.2", + "algoliasearch": "^4.18.0", + "algoliasearch-helper": "^3.13.3", + "clsx": "^2.0.0", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-translations": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.5.2.tgz", + "integrity": "sha512-GPZLcu4aT1EmqSTmbdpVrDENGR2yObFEX8ssEFYTCiAIVc0EihNSdOIBTazUvgNqwvnoU1A8vIs1xyzc3LITTw==", + "dependencies": { + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/types": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.5.2.tgz", + "integrity": "sha512-N6GntLXoLVUwkZw7zCxwy9QiuEXIcTVzA9AkmNw16oc0AP3SXLrMmDMMBIfgqwuKWa6Ox6epHol9kMtJqekACw==", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/utils": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.5.2.tgz", + "integrity": "sha512-33QvcNFh+Gv+C2dP9Y9xWEzMgf3JzrpL2nW9PopidiohS1nDcyknKRx2DWaFvyVTTYIkkABVSr073VTj/NITNA==", + "dependencies": { + "@docusaurus/logger": "3.5.2", + "@docusaurus/utils-common": "3.5.2", + "@svgr/webpack": "^8.1.0", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "prompts": "^2.4.2", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/utils-common": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.5.2.tgz", + "integrity": "sha512-i0AZjHiRgJU6d7faQngIhuHKNrszpL/SHQPgF1zH4H+Ij6E9NBYGy6pkcGWToIv7IVPbs+pQLh1P3whn0gWXVg==", + "dependencies": { + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/utils-validation": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.5.2.tgz", + "integrity": "sha512-m+Foq7augzXqB6HufdS139PFxDC5d5q2QKZy8q0qYYvGdI6nnlNsGH4cIGsgBnV7smz+mopl3g4asbSDvMV0jA==", + "dependencies": { + "@docusaurus/logger": "3.5.2", + "@docusaurus/utils": "3.5.2", + "@docusaurus/utils-common": "3.5.2", + "fs-extra": "^11.2.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.1.tgz", + "integrity": "sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-to-js": "^2.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-estree": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "periscopic": "^3.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz", + "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==" + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@slorber/remark-comment": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", + "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.1.0", + "micromark-util-symbol": "^1.0.1" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/gtag.js": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", + "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "node_modules/@types/node": { + "version": "22.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.6.0.tgz", + "integrity": "sha512-QyR8d5bmq+eR72TwQDfujwShHMcIrWIYsaQFtXRE58MHPTEKUNxjxvl0yS0qPMds5xbSDWtp7ZpvGFtd7dfMdQ==", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prismjs": { + "version": "1.26.4", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.4.tgz", + "integrity": "sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" + }, + "node_modules/@types/qs": { + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" + }, + "node_modules/@types/react": { + "version": "18.3.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.8.tgz", + "integrity": "sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz", + "integrity": "sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "^5.1.0" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + }, + "node_modules/@types/ws": { + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/algoliasearch": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.24.0.tgz", + "integrity": "sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.24.0", + "@algolia/cache-common": "4.24.0", + "@algolia/cache-in-memory": "4.24.0", + "@algolia/client-account": "4.24.0", + "@algolia/client-analytics": "4.24.0", + "@algolia/client-common": "4.24.0", + "@algolia/client-personalization": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/logger-common": "4.24.0", + "@algolia/logger-console": "4.24.0", + "@algolia/recommend": "4.24.0", + "@algolia/requester-browser-xhr": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/requester-node-http": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/algoliasearch-helper": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.22.5.tgz", + "integrity": "sha512-lWvhdnc+aKOKx8jyA3bsdEgHzm/sglC4cYdMG4xSQyRiPLJVJtH/IVYZG3Hp6PkTEhQqhyVYkeP9z2IlcHJsWw==", + "dependencies": { + "@algolia/events": "^4.0.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 6" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/requester-browser-xhr": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", + "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/requester-node-http": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", + "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001663", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz", + "integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "node_modules/combine-promises": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz", + "integrity": "sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compressible/node_modules/mime-db": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-text-to-clipboard": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", + "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", + "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "dependencies": { + "browserslist": "^4.23.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.38.1.tgz", + "integrity": "sha512-BY8Etc1FZqdw1glX0XNOq2FDwfrg/VGqoZOZCdaL+UmdaqDwQwYXkMJT4t6In+zfEfOJDcM9T0KdbBeJg8KKCQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-declaration-sorter": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", + "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "cssnano": "^6.0.1", + "jest-worker": "^29.4.3", + "postcss": "^8.4.24", + "schema-utils": "^4.0.1", + "serialize-javascript": "^6.0.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", + "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "dependencies": { + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-advanced": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz", + "integrity": "sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==", + "dependencies": { + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.0", + "cssnano-preset-default": "^6.1.2", + "postcss-discard-unused": "^6.0.5", + "postcss-merge-idents": "^6.0.3", + "postcss-reduce-idents": "^6.0.3", + "postcss-zindex": "^6.0.2" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", + "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "dependencies": { + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", + "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-port": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", + "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.27", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz", + "integrity": "sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/emoticon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz", + "integrity": "sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.1.2.tgz", + "integrity": "sha512-S0gW2+XZkmsx00tU2uJ4L9hUT7IFabbml9pHh2WQqFmAbxit++YGZne0sKJbNwkj9Wvg9E4uqWl4nCIFQMmfag==", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "dependencies": { + "@types/node": "*", + "require-like": ">= 0.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + }, + "node_modules/express/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/file-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/file-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.4.tgz", + "integrity": "sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", + "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==" + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", + "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/infima": { + "version": "0.2.0-alpha.44", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.44.tgz", + "integrity": "sha512-tuRkUSO/lB3rEhLJk25atwAjgLuzq070+pOW8XcvpHky/YbENnRRdPd85IBkyeTgttmOy5ah+yHYsK1HhUd4lQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/launch-editor": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", + "integrity": "sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", + "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.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.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", + "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", + "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", + "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz", + "integrity": "sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-space/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", + "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.1.tgz", + "integrity": "sha512-+Vyi+GCCOHnrJ2VPS+6aPoXN2k2jgUzDRhTFLjjTBn23qyXJXkjUWQgTL+mXpF5/A8ixLdCc6kWsoeOjKGejKQ==", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-emoji": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", + "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", + "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", + "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", + "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", + "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", + "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", + "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-unused": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", + "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-loader": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", + "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", + "dependencies": { + "cosmiconfig": "^8.3.5", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-merge-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz", + "integrity": "sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", + "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", + "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", + "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", + "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", + "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "dependencies": { + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", + "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", + "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", + "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", + "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", + "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", + "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", + "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", + "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", + "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", + "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", + "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz", + "integrity": "sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", + "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", + "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-sort-media-queries": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz", + "integrity": "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==", + "dependencies": { + "sort-css-media-queries": "2.2.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.23" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", + "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", + "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/postcss-zindex": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz", + "integrity": "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/prism-react-renderer": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.0.tgz", + "integrity": "sha512-327BsVCD/unU4CNLZTWVHyUHKnsqcvj2qbPlQ8MiBE2eq2rgctjigPA1Gp9HLF83kZ20zNN6jgizHJeEsyFYOw==", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/react-dev-utils/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-json-view-lite": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-1.5.0.tgz", + "integrity": "sha512-nWqA1E4jKPklL2jvHWs6s+7Na0qNgw9HCP6xehdQJeg6nPBTFZgGwyko9Q0oj+jQWKTTVRS30u0toM5wiuL3iw==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", + "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", + "dependencies": { + "@types/react": "*" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "dependencies": { + "@babel/runtime": "^7.10.3" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "react-loadable": "*", + "webpack": ">=4.41.1 || 5.x" + } + }, + "node_modules/react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router": ">=5" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.0.tgz", + "integrity": "sha512-l1UyWJ6Eg1VPU7Hm/9tt0zKtReJQNOA4+iDMAxTyZNWnJnFlbS/7zhiel/rogTLQ2vMYwDzSJa4BiVNqGlqIMA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-emoji": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", + "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", + "dependencies": { + "@types/mdast": "^4.0.2", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.0", + "unified": "^11.0.4" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.1.tgz", + "integrity": "sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rtl-detect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.1.2.tgz", + "integrity": "sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==" + }, + "node_modules/rtlcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/search-insights": { + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.2.tgz", + "integrity": "sha512-zFNpOpUO+tY2D85KrxJ+aqwnIfdEGi06UH2+xEb+Bp9Mwznmauqc9djbnBibJO5mpfUPPa8st6Sx65+vbeO45g==", + "peer": true + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-handler": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/sitemap": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.2.tgz", + "integrity": "sha512-ARCqzHJ0p4gWt+j7NlU5eDlIO9+Rkr/JhPFZKKQ1l5GCus7rJH4UdrlVAh0xC/gDS/Qir2UMxqYNHtsKr2rpCw==", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sort-css-media-queries": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz", + "integrity": "sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==", + "engines": { + "node": ">= 6.3.0" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/stylehacks": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", + "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz", + "integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/url-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/url-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpack": { + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "dependencies": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpackbar": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", + "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", + "dependencies": { + "chalk": "^4.1.0", + "consola": "^2.15.3", + "pretty-time": "^1.1.0", + "std-env": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "webpack": "3 || 4 || 5" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/package.json b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/package.json new file mode 100644 index 0000000..4acf04c --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/package.json @@ -0,0 +1,42 @@ +{ + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids" + }, + "dependencies": { + "@docusaurus/core": "3.5.2", + "@docusaurus/preset-classic": "3.5.2", + "@mdx-js/react": "3.0.1", + "clsx": "2.1.1", + "prism-react-renderer": "2.4.0", + "react": "18.3.1", + "react-dom": "18.3.1" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "3.5.2", + "@docusaurus/types": "3.5.2" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 3 chrome version", + "last 3 firefox version", + "last 5 safari version" + ] + }, + "engines": { + "node": ">=18.0" + } +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/sidebars.js b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/sidebars.js new file mode 100644 index 0000000..3efb4ff --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/sidebars.js @@ -0,0 +1,20 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +// @ts-check + +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const sidebars = { + // By default, Docusaurus generates a sidebar from the docs folder structure + docsSidebar: [{type: 'autogenerated', dirName: '.'}], +}; + +export default sidebars; diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/src/css/custom.css b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/src/css/custom.css new file mode 100644 index 0000000..2bc6a4c --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/src/css/custom.css @@ -0,0 +1,30 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #2e8555; + --ifm-color-primary-dark: #29784c; + --ifm-color-primary-darker: #277148; + --ifm-color-primary-darkest: #205d3b; + --ifm-color-primary-light: #33925d; + --ifm-color-primary-lighter: #359962; + --ifm-color-primary-lightest: #3cad6e; + --ifm-code-font-size: 95%; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme='dark'] { + --ifm-color-primary: #25c2a0; + --ifm-color-primary-dark: #21af90; + --ifm-color-primary-darker: #1fa588; + --ifm-color-primary-darkest: #1a8870; + --ifm-color-primary-light: #29d5b0; + --ifm-color-primary-lighter: #32d8b4; + --ifm-color-primary-lightest: #4fddbf; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/static/.nojekyll b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/static/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/docs/static/img/favicon.ico b/host/cred-script/vendor/rquickjs-sys/quickjs/docs/static/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c01d54bcd39a5f853428f3cd5aa0f383d963c484 GIT binary patch literal 3626 zcmZQzU}RuqP>=@E3JfBA3=Con3=A3!3=9ek3=C!r5OD?u28IS+1_mK+2nO*%IR1>C zVEh@o?)Woy@8Zwc{U-}waQL5a&G~=A4VVA%w*&u2yqfbr@bB0E0ssFa;lKZbzu*2J z{kZyT!VTvo2{&A15^lIKK<)lbmc1bNp0kJB4YEJshV%b~o9_R^->yQk8{v+ipO5~> z-b?zQaNTiE!VMR;_%n9zp?3d^KVt{NB!xl3B}cHoA$Ge!*-roC?nL|#d9(e$*Q;0m zJzu>7(|$jHg54DPY9`43PYE|%K;ix;{*2v$_%n9f;?LNT91aPWvDxqPKjEg!|F9cX z|LqPR{BL{k;D6i0hyQ!Oe-E}l{OyYW2{)WTZhaVk#;z*+-plK3-rKS{R# zjP3t~s}4~AIR8($4)T}l|ELEQ|Gn=Y{qJ(~)_<3qH~+iby7k}pDtO$a{0zo7Z~k|^eH-roz~67DG5r6}kZ{!*WG@V7#GkSIMymf|_Ithm^xy8( zx&L-2&iuDOdFsFY$&)D9;q+;E{0IK|)*tp|Cqu$D6#J9n&)9t-)&9tb{r^Kgo%tX5 z;=q6JYpehJ-{0`x{^&k%dIzO>7`8il6rTP=zFyp#c+JKGn*U+`FONTC_lq?9?f%D~ zb^ITH&iQ}*C71uPmmL4cUUvEKe{IHpms__X=?;|k(853b?TUX1*PUJ`+;9m;N`JBO zXY4+cY(Jfo)A4`srHcQSTekeS*t7|bEw^p^@Ac*lIIV!wKP3Nm zBH5oGf5z?y$@ZUh`X75KSAdjkIb`;UU5^+EW%HQy4hJ6=w> z;o^W~e_s3JnI0n7e*(Np8r60 z+y2iy@AbdzO4R@As|o*`Z)E=OzFqWx;+?AhGw-+jU-D$a|J6@t{@?t3@&A2qHvB*K zZs-5wZ+Ca!`g|E?FO1HNC$ani`Mc&?;{S_pPyT=S=I;Nme?R|!^Xb+9+xKt%|NZCJ z|DQj9{=a(V>i^H5KK}=SE0?bPzkl~Wh}rS~|9_ahFq-7@H}7s{(t)T>Hpn3cmL0wJGZ01uODP5GA@PHzi}sR z|NE~r{vUhX=6}LjyZ=EOO#g@Pw)`J|7Sj#MXPy7|+$#CM;>pzin_evZzw6cN{|8@h z`G5NT{{NRgo&10E^Tq!UzTN!)^xK2~Z+^b`|Ka!B|8Kv&?)>xr7qZR^RfAkTX|H?k%|J|nR{ZBZL2ovOT0+jASX&pp^(l|&i@vOuDiTPiBHGV?RtrC!($T$+-7CdYB-?mBPzqGZ`e|cw-|7t;!|0DNX zVf8=AE^IjJpw<7VL)PFpj5}rfKjyeKIRAm-EcUd`gqYLT$aaI+(J=pm%!@m1_uqfD z$$zhT2LGcDT9afqDDAk<)c@}_-{61Z1^fTOo6P<@bZUX!0x~=Pj9nS5+yx~*yFa4@B`IVXYB68pRv<{+6l5A +#include +#include +#include +#include +#include +#include +// #include +#include +// #include + +#include "cutils.h" +#include "dtoa.h" + +/* + TODO: + - simplify subnormal handling + - reduce max memory usage + - free format: could add shortcut if exact result + - use 64 bit limb_t when possible + - use another algorithm for free format dtoa in base 10 (ryu ?) +*/ + +#define USE_POW5_TABLE +/* use fast path to print small integers in free format */ +#define USE_FAST_INT + +#define LIMB_LOG2_BITS 5 + +#define LIMB_BITS (1 << LIMB_LOG2_BITS) + +typedef int32_t slimb_t; +typedef uint32_t limb_t; +typedef uint64_t dlimb_t; + +#define LIMB_DIGITS 9 + +#define JS_RADIX_MAX 36 + +#define DBIGNUM_LEN_MAX 52 /* ~ 2^(1072+53)*36^100 (dtoa) */ +#define MANT_LEN_MAX 18 /* < 36^100 */ + +typedef intptr_t mp_size_t; + +/* the represented number is sum(i, tab[i]*2^(LIMB_BITS * i)) */ +typedef struct { + int len; /* >= 1 */ + limb_t tab[]; +} mpb_t; + +static limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n) +{ + size_t i; + limb_t k, a; + + k=b; + for(i=0;i> LIMB_BITS; + } + return l; +} + +/* WARNING: d must be >= 2^(LIMB_BITS-1) */ +static inline limb_t udiv1norm_init(limb_t d) +{ + limb_t a0, a1; + a1 = -d - 1; + a0 = -1; + return (((dlimb_t)a1 << LIMB_BITS) | a0) / d; +} + +/* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0 + / d' with 0 <= a1 < d. */ +static inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0, + limb_t d, limb_t d_inv) +{ + limb_t n1m, n_adj, q, r, ah; + dlimb_t a; + n1m = ((slimb_t)a0 >> (LIMB_BITS - 1)); + n_adj = a0 + (n1m & d); + a = (dlimb_t)d_inv * (a1 - n1m) + n_adj; + q = (a >> LIMB_BITS) + a1; + /* compute a - q * r and update q so that the remainder is between + 0 and d - 1 */ + a = ((dlimb_t)a1 << LIMB_BITS) | a0; + a = a - (dlimb_t)q * d - d; + ah = a >> LIMB_BITS; + q += 1 + ah; + r = (limb_t)a + (ah & d); + *pr = r; + return q; +} + +static limb_t mp_div1(limb_t *tabr, const limb_t *taba, limb_t n, + limb_t b, limb_t r) +{ + slimb_t i; + dlimb_t a1; + for(i = n - 1; i >= 0; i--) { + a1 = ((dlimb_t)r << LIMB_BITS) | taba[i]; + tabr[i] = a1 / b; + r = a1 % b; + } + return r; +} + +/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). + 1 <= shift <= LIMB_BITS - 1 */ +static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, + int shift, limb_t high) +{ + mp_size_t i; + limb_t l, a; + + assert(shift >= 1 && shift < LIMB_BITS); + l = high; + for(i = n - 1; i >= 0; i--) { + a = tab[i]; + tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift)); + l = a; + } + return l & (((limb_t)1 << shift) - 1); +} + +/* r = (a << shift) + low. 1 <= shift <= LIMB_BITS - 1, 0 <= low < + 2^shift. */ +static limb_t mp_shl(limb_t *tab_r, const limb_t *tab, mp_size_t n, + int shift, limb_t low) +{ + mp_size_t i; + limb_t l, a; + + assert(shift >= 1 && shift < LIMB_BITS); + l = low; + for(i = 0; i < n; i++) { + a = tab[i]; + tab_r[i] = (a << shift) | l; + l = (a >> (LIMB_BITS - shift)); + } + return l; +} + +static no_inline limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n, + limb_t b, limb_t r, limb_t b_inv, int shift) +{ + slimb_t i; + + if (shift != 0) { + r = (r << shift) | mp_shl(tabr, taba, n, shift, 0); + } + for(i = n - 1; i >= 0; i--) { + tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv); + } + r >>= shift; + return r; +} + +static __maybe_unused void mpb_dump(const char *str, const mpb_t *a) +{ + int i; + + printf("%s= 0x", str); + for(i = a->len - 1; i >= 0; i--) { + printf("%08x", a->tab[i]); + if (i != 0) + printf("_"); + } + printf("\n"); +} + +static void mpb_renorm(mpb_t *r) +{ + while (r->len > 1 && r->tab[r->len - 1] == 0) + r->len--; +} + +#ifdef USE_POW5_TABLE +static const uint32_t pow5_table[17] = { + 0x00000005, 0x00000019, 0x0000007d, 0x00000271, + 0x00000c35, 0x00003d09, 0x0001312d, 0x0005f5e1, + 0x001dcd65, 0x009502f9, 0x02e90edd, 0x0e8d4a51, + 0x48c27395, 0x6bcc41e9, 0x1afd498d, 0x86f26fc1, + 0xa2bc2ec5, +}; + +static const uint8_t pow5h_table[4] = { + 0x00000001, 0x00000007, 0x00000023, 0x000000b1, +}; + +static const uint32_t pow5_inv_table[13] = { + 0x99999999, 0x47ae147a, 0x0624dd2f, 0xa36e2eb1, + 0x4f8b588e, 0x0c6f7a0b, 0xad7f29ab, 0x5798ee23, + 0x12e0be82, 0xb7cdfd9d, 0x5fd7fe17, 0x19799812, + 0xc25c2684, +}; +#endif + +/* return a^b */ +static uint64_t pow_ui(uint32_t a, uint32_t b) +{ + int i, n_bits; + uint64_t r; + if (b == 0) + return 1; + if (b == 1) + return a; +#ifdef USE_POW5_TABLE + if ((a == 5 || a == 10) && b <= 17) { + r = pow5_table[b - 1]; + if (b >= 14) { + r |= (uint64_t)pow5h_table[b - 14] << 32; + } + if (a == 10) + r <<= b; + return r; + } +#endif + r = a; + n_bits = 32 - clz32(b); + for(i = n_bits - 2; i >= 0; i--) { + r *= r; + if ((b >> i) & 1) + r *= a; + } + return r; +} + +static uint32_t pow_ui_inv(uint32_t *pr_inv, int *pshift, uint32_t a, uint32_t b) +{ + uint32_t r_inv, r; + int shift; +#ifdef USE_POW5_TABLE + if (a == 5 && b >= 1 && b <= 13) { + r = pow5_table[b - 1]; + shift = clz32(r); + r <<= shift; + r_inv = pow5_inv_table[b - 1]; + } else +#endif + { + r = pow_ui(a, b); + shift = clz32(r); + r <<= shift; + r_inv = udiv1norm_init(r); + } + *pshift = shift; + *pr_inv = r_inv; + return r; +} + +enum { + JS_RNDN, /* round to nearest, ties to even */ + JS_RNDNA, /* round to nearest, ties away from zero */ + JS_RNDZ, +}; + +static int mpb_get_bit(const mpb_t *r, int k) +{ + int l; + + l = (unsigned)k / LIMB_BITS; + k = k & (LIMB_BITS - 1); + if (l >= r->len) + return 0; + else + return (r->tab[l] >> k) & 1; +} + +/* compute round(r / 2^shift). 'shift' can be negative */ +static void mpb_shr_round(mpb_t *r, int shift, int rnd_mode) +{ + int l, i; + + if (shift == 0) + return; + if (shift < 0) { + shift = -shift; + l = (unsigned)shift / LIMB_BITS; + shift = shift & (LIMB_BITS - 1); + if (shift != 0) { + r->tab[r->len] = mp_shl(r->tab, r->tab, r->len, shift, 0); + r->len++; + mpb_renorm(r); + } + if (l > 0) { + for(i = r->len - 1; i >= 0; i--) + r->tab[i + l] = r->tab[i]; + for(i = 0; i < l; i++) + r->tab[i] = 0; + r->len += l; + } + } else { + limb_t bit1, bit2; + int k, add_one; + + switch(rnd_mode) { + default: + case JS_RNDZ: + add_one = 0; + break; + case JS_RNDN: + case JS_RNDNA: + bit1 = mpb_get_bit(r, shift - 1); + if (bit1) { + if (rnd_mode == JS_RNDNA) { + bit2 = 1; + } else { + /* bit2 = oring of all the bits after bit1 */ + bit2 = 0; + if (shift >= 2) { + k = shift - 1; + l = (unsigned)k / LIMB_BITS; + k = k & (LIMB_BITS - 1); + for(i = 0; i < min_int(l, r->len); i++) + bit2 |= r->tab[i]; + if (l < r->len) + bit2 |= r->tab[l] & (((limb_t)1 << k) - 1); + } + } + if (bit2) { + add_one = 1; + } else { + /* round to even */ + add_one = mpb_get_bit(r, shift); + } + } else { + add_one = 0; + } + break; + } + + l = (unsigned)shift / LIMB_BITS; + shift = shift & (LIMB_BITS - 1); + if (l >= r->len) { + r->len = 1; + r->tab[0] = add_one; + } else { + if (l > 0) { + r->len -= l; + for(i = 0; i < r->len; i++) + r->tab[i] = r->tab[i + l]; + } + if (shift != 0) { + mp_shr(r->tab, r->tab, r->len, shift, 0); + mpb_renorm(r); + } + if (add_one) { + limb_t a; + a = mp_add_ui(r->tab, 1, r->len); + if (a) + r->tab[r->len++] = a; + } + } + } +} + +/* return -1, 0 or 1 */ +static int mpb_cmp(const mpb_t *a, const mpb_t *b) +{ + mp_size_t i; + if (a->len < b->len) + return -1; + else if (a->len > b->len) + return 1; + for(i = a->len - 1; i >= 0; i--) { + if (a->tab[i] != b->tab[i]) { + if (a->tab[i] < b->tab[i]) + return -1; + else + return 1; + } + } + return 0; +} + +static void mpb_set_u64(mpb_t *r, uint64_t m) +{ +#if LIMB_BITS == 64 + r->tab[0] = m; + r->len = 1; +#else + r->tab[0] = m; + r->tab[1] = m >> LIMB_BITS; + if (r->tab[1] == 0) + r->len = 1; + else + r->len = 2; +#endif +} + +static uint64_t mpb_get_u64(mpb_t *r) +{ +#if LIMB_BITS == 64 + return r->tab[0]; +#else + if (r->len == 1) { + return r->tab[0]; + } else { + return r->tab[0] | ((uint64_t)r->tab[1] << LIMB_BITS); + } +#endif +} + +/* floor_log2() = position of the first non zero bit or -1 if zero. */ +static int mpb_floor_log2(mpb_t *a) +{ + limb_t v; + v = a->tab[a->len - 1]; + if (v == 0) + return -1; + else + return a->len * LIMB_BITS - 1 - clz32(v); +} + +#define MUL_LOG2_RADIX_BASE_LOG2 24 + +/* round((1 << MUL_LOG2_RADIX_BASE_LOG2)/log2(i + 2)) */ +static const uint32_t mul_log2_radix_table[JS_RADIX_MAX - 1] = { + 0x000000, 0xa1849d, 0x000000, 0x6e40d2, + 0x6308c9, 0x5b3065, 0x000000, 0x50c24e, + 0x4d104d, 0x4a0027, 0x4768ce, 0x452e54, + 0x433d00, 0x418677, 0x000000, 0x3ea16b, + 0x3d645a, 0x3c43c2, 0x3b3b9a, 0x3a4899, + 0x39680b, 0x3897b3, 0x37d5af, 0x372069, + 0x367686, 0x35d6df, 0x354072, 0x34b261, + 0x342bea, 0x33ac62, 0x000000, 0x32bfd9, + 0x3251dd, 0x31e8d6, 0x318465, +}; + +/* return floor(a / log2(radix)) for -2048 <= a <= 2047 */ +static int mul_log2_radix(int a, int radix) +{ + int radix_bits, mult; + + if ((radix & (radix - 1)) == 0) { + /* if the radix is a power of two better to do it exactly */ + radix_bits = 31 - clz32(radix); + if (a < 0) + a -= radix_bits - 1; + return a / radix_bits; + } else { + mult = mul_log2_radix_table[radix - 2]; + return ((int64_t)a * mult) >> MUL_LOG2_RADIX_BASE_LOG2; + } +} + +#if 0 +static void build_mul_log2_radix_table(void) +{ + int base, radix, mult, col, base_log2; + + base_log2 = 24; + base = 1 << base_log2; + col = 0; + for(radix = 2; radix <= 36; radix++) { + if ((radix & (radix - 1)) == 0) + mult = 0; + else + mult = lrint((double)base / log2(radix)); + printf("0x%06x, ", mult); + if (++col == 4) { + printf("\n"); + col = 0; + } + } + printf("\n"); +} + +static void mul_log2_radix_test(void) +{ + int radix, i, ref, r; + + for(radix = 2; radix <= 36; radix++) { + for(i = -2048; i <= 2047; i++) { + ref = (int)floor((double)i / log2(radix)); + r = mul_log2_radix(i, radix); + if (ref != r) { + printf("ERROR: radix=%d i=%d r=%d ref=%d\n", + radix, i, r, ref); + exit(1); + } + } + } + if (0) + build_mul_log2_radix_table(); +} +#endif + +static void u32toa_len(char *buf, uint32_t n, size_t len) +{ + int digit, i; + for(i = len - 1; i >= 0; i--) { + digit = n % 10; + n = n / 10; + buf[i] = digit + '0'; + } +} + +/* for power of 2 radixes. len >= 1 */ +static void u64toa_bin_len(char *buf, uint64_t n, unsigned int radix_bits, int len) +{ + int digit, i; + unsigned int mask; + + mask = (1 << radix_bits) - 1; + for(i = len - 1; i >= 0; i--) { + digit = n & mask; + n >>= radix_bits; + if (digit < 10) + digit += '0'; + else + digit += 'a' - 10; + buf[i] = digit; + } +} + +/* len >= 1. 2 <= radix <= 36 */ +static void limb_to_a(char *buf, limb_t n, unsigned int radix, int len) +{ + int digit, i; + + if (radix == 10) { + /* specific case with constant divisor */ +#if LIMB_BITS == 32 + u32toa_len(buf, n, len); +#else + /* XXX: optimize */ + for(i = len - 1; i >= 0; i--) { + digit = (limb_t)n % 10; + n = (limb_t)n / 10; + buf[i] = digit + '0'; + } +#endif + } else { + for(i = len - 1; i >= 0; i--) { + digit = (limb_t)n % radix; + n = (limb_t)n / radix; + if (digit < 10) + digit += '0'; + else + digit += 'a' - 10; + buf[i] = digit; + } + } +} + +size_t u32toa(char *buf, uint32_t n) +{ + char buf1[10], *q; + size_t len; + + q = buf1 + sizeof(buf1); + do { + *--q = n % 10 + '0'; + n /= 10; + } while (n != 0); + len = buf1 + sizeof(buf1) - q; + memcpy(buf, q, len); + return len; +} + +size_t i32toa(char *buf, int32_t n) +{ + if (n >= 0) { + return u32toa(buf, n); + } else { + buf[0] = '-'; + return u32toa(buf + 1, -(uint32_t)n) + 1; + } +} + +#ifdef USE_FAST_INT +size_t u64toa(char *buf, uint64_t n) +{ + if (n < 0x100000000) { + return u32toa(buf, n); + } else { + uint64_t n1; + char *q = buf; + uint32_t n2; + + n1 = n / 1000000000; + n %= 1000000000; + if (n1 >= 0x100000000) { + n2 = n1 / 1000000000; + n1 = n1 % 1000000000; + /* at most two digits */ + if (n2 >= 10) { + *q++ = n2 / 10 + '0'; + n2 %= 10; + } + *q++ = n2 + '0'; + u32toa_len(q, n1, 9); + q += 9; + } else { + q += u32toa(q, n1); + } + u32toa_len(q, n, 9); + q += 9; + return q - buf; + } +} + +size_t i64toa(char *buf, int64_t n) +{ + if (n >= 0) { + return u64toa(buf, n); + } else { + buf[0] = '-'; + return u64toa(buf + 1, -(uint64_t)n) + 1; + } +} + +/* XXX: only tested for 1 <= n < 2^53 */ +size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix) +{ + int radix_bits, l; + if (likely(radix == 10)) + return u64toa(buf, n); + if ((radix & (radix - 1)) == 0) { + radix_bits = 31 - clz32(radix); + if (n == 0) + l = 1; + else + l = (64 - clz64(n) + radix_bits - 1) / radix_bits; + u64toa_bin_len(buf, n, radix_bits, l); + return l; + } else { + char buf1[41], *q; /* maximum length for radix = 3 */ + size_t len; + int digit; + q = buf1 + sizeof(buf1); + do { + digit = n % radix; + n /= radix; + if (digit < 10) + digit += '0'; + else + digit += 'a' - 10; + *--q = digit; + } while (n != 0); + len = buf1 + sizeof(buf1) - q; + memcpy(buf, q, len); + return len; + } +} + +size_t i64toa_radix(char *buf, int64_t n, unsigned int radix) +{ + if (n >= 0) { + return u64toa_radix(buf, n, radix); + } else { + buf[0] = '-'; + return u64toa_radix(buf + 1, -(uint64_t)n, radix) + 1; + } +} +#endif /* USE_FAST_INT */ + +static const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = { +#if LIMB_BITS == 32 +32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +#else +64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12, +#endif +}; + +static const uint32_t radix_base_table[JS_RADIX_MAX - 1] = { + 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395, + 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91, + 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021, + 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571, + 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d, + 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51, + 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899, + 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1, + 0x5c13d840, 0x6d91b519, 0x81bf1000, +}; + +/* XXX: remove the table ? */ +static uint8_t dtoa_max_digits_table[JS_RADIX_MAX - 1] = { + 54, 35, 28, 24, 22, 20, 19, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, +}; + +/* we limit the maximum number of significant digits for atod to about + 128 bits of precision for non power of two bases. The only + requirement for Javascript is at least 20 digits in base 10. For + power of two bases, we do an exact rounding in all the cases. */ +static uint8_t atod_max_digits_table[JS_RADIX_MAX - 1] = { + 64, 80, 32, 55, 49, 45, 21, 40, 38, 37, 35, 34, 33, 32, 16, 31, 30, 30, 29, 29, 28, 28, 27, 27, 27, 26, 26, 26, 26, 25, 12, 25, 25, 24, 24, +}; + +/* if abs(d) >= B^max_exponent, it is an overflow */ +static const int16_t max_exponent[JS_RADIX_MAX - 1] = { + 1024, 647, 512, 442, 397, 365, 342, 324, + 309, 297, 286, 277, 269, 263, 256, 251, + 246, 242, 237, 234, 230, 227, 224, 221, + 218, 216, 214, 211, 209, 207, 205, 203, + 202, 200, 199, +}; + +/* if abs(d) <= B^min_exponent, it is an underflow */ +static const int16_t min_exponent[JS_RADIX_MAX - 1] = { +-1075, -679, -538, -463, -416, -383, -359, -340, + -324, -311, -300, -291, -283, -276, -269, -263, + -258, -254, -249, -245, -242, -238, -235, -232, + -229, -227, -224, -222, -220, -217, -215, -214, + -212, -210, -208, +}; + +#if 0 +void build_tables(void) +{ + int r, j, radix, n, col, i; + + /* radix_base_table */ + for(radix = 2; radix <= 36; radix++) { + r = 1; + for(j = 0; j < digits_per_limb_table[radix - 2]; j++) { + r *= radix; + } + printf(" 0x%08x,", r); + if ((radix % 4) == 1) + printf("\n"); + } + printf("\n"); + + /* dtoa_max_digits_table */ + for(radix = 2; radix <= 36; radix++) { + /* Note: over estimated when the radix is a power of two */ + printf(" %d,", 1 + (int)ceil(53.0 / log2(radix))); + } + printf("\n"); + + /* atod_max_digits_table */ + for(radix = 2; radix <= 36; radix++) { + if ((radix & (radix - 1)) == 0) { + /* 64 bits is more than enough */ + n = (int)floor(64.0 / log2(radix)); + } else { + n = (int)floor(128.0 / log2(radix)); + } + printf(" %d,", n); + } + printf("\n"); + + printf("static const int16_t max_exponent[JS_RADIX_MAX - 1] = {\n"); + col = 0; + for(radix = 2; radix <= 36; radix++) { + printf("%5d, ", (int)ceil(1024 / log2(radix))); + if (++col == 8) { + col = 0; + printf("\n"); + } + } + printf("\n};\n\n"); + + printf("static const int16_t min_exponent[JS_RADIX_MAX - 1] = {\n"); + col = 0; + for(radix = 2; radix <= 36; radix++) { + printf("%5d, ", (int)floor(-1075 / log2(radix))); + if (++col == 8) { + col = 0; + printf("\n"); + } + } + printf("\n};\n\n"); + + printf("static const uint32_t pow5_table[16] = {\n"); + col = 0; + for(i = 2; i <= 17; i++) { + r = 1; + for(j = 0; j < i; j++) { + r *= 5; + } + printf("0x%08x, ", r); + if (++col == 4) { + col = 0; + printf("\n"); + } + } + printf("\n};\n\n"); + + /* high part */ + printf("static const uint8_t pow5h_table[4] = {\n"); + col = 0; + for(i = 14; i <= 17; i++) { + uint64_t r1; + r1 = 1; + for(j = 0; j < i; j++) { + r1 *= 5; + } + printf("0x%08x, ", (uint32_t)(r1 >> 32)); + if (++col == 4) { + col = 0; + printf("\n"); + } + } + printf("\n};\n\n"); +} +#endif + +/* n_digits >= 1. 0 <= dot_pos <= n_digits. If dot_pos == n_digits, + the dot is not displayed. 'a' is modified. */ +static int output_digits(char *buf, + mpb_t *a, int radix, int n_digits1, + int dot_pos) +{ + int n_digits, digits_per_limb, radix_bits, n, len; + + n_digits = n_digits1; + if ((radix & (radix - 1)) == 0) { + /* radix = 2^radix_bits */ + radix_bits = 31 - clz32(radix); + } else { + radix_bits = 0; + } + digits_per_limb = digits_per_limb_table[radix - 2]; + if (radix_bits != 0) { + for(;;) { + n = min_int(n_digits, digits_per_limb); + n_digits -= n; + u64toa_bin_len(buf + n_digits, a->tab[0], radix_bits, n); + if (n_digits == 0) + break; + mpb_shr_round(a, digits_per_limb * radix_bits, JS_RNDZ); + } + } else { + limb_t r; + while (n_digits != 0) { + n = min_int(n_digits, digits_per_limb); + n_digits -= n; + r = mp_div1(a->tab, a->tab, a->len, radix_base_table[radix - 2], 0); + mpb_renorm(a); + limb_to_a(buf + n_digits, r, radix, n); + } + } + + /* add the dot */ + len = n_digits1; + if (dot_pos != n_digits1) { + memmove(buf + dot_pos + 1, buf + dot_pos, n_digits1 - dot_pos); + buf[dot_pos] = '.'; + len++; + } + return len; +} + +/* return (a, e_offset) such that a = a * (radix1*2^radix_shift)^f * + 2^-e_offset. 'f' can be negative. */ +static int mul_pow(mpb_t *a, int radix1, int radix_shift, int f, bool is_int, int e) +{ + int e_offset, d, n, n0; + + e_offset = -f * radix_shift; + if (radix1 != 1) { + d = digits_per_limb_table[radix1 - 2]; + if (f >= 0) { + limb_t h, b; + + b = 0; + n0 = 0; + while (f != 0) { + n = min_int(f, d); + if (n != n0) { + b = pow_ui(radix1, n); + n0 = n; + } + h = mp_mul1(a->tab, a->tab, a->len, b, 0); + if (h != 0) { + a->tab[a->len++] = h; + } + f -= n; + } + } else { + int extra_bits, l, shift; + limb_t r, rem, b, b_inv; + + f = -f; + l = (f + d - 1) / d; /* high bound for the number of limbs (XXX: make it better) */ + e_offset += l * LIMB_BITS; + if (!is_int) { + /* at least 'e' bits are needed in the final result for rounding */ + extra_bits = max_int(e - mpb_floor_log2(a), 0); + } else { + /* at least two extra bits are needed in the final result + for rounding */ + extra_bits = max_int(2 + e - e_offset, 0); + } + e_offset += extra_bits; + mpb_shr_round(a, -(l * LIMB_BITS + extra_bits), JS_RNDZ); + + b = 0; + b_inv = 0; + shift = 0; + n0 = 0; + rem = 0; + while (f != 0) { + n = min_int(f, d); + if (n != n0) { + b = pow_ui_inv(&b_inv, &shift, radix1, n); + n0 = n; + } + r = mp_div1norm(a->tab, a->tab, a->len, b, 0, b_inv, shift); + rem |= r; + mpb_renorm(a); + f -= n; + } + /* if the remainder is non zero, use it for rounding */ + a->tab[0] |= (rem != 0); + } + } + return e_offset; +} + +/* tmp1 = round(m*2^e*radix^f). 'tmp0' is a temporary storage */ +static void mul_pow_round(mpb_t *tmp1, uint64_t m, int e, int radix1, int radix_shift, int f, + int rnd_mode) +{ + int e_offset; + + mpb_set_u64(tmp1, m); + e_offset = mul_pow(tmp1, radix1, radix_shift, f, true, e); + mpb_shr_round(tmp1, -e + e_offset, rnd_mode); +} + +/* return round(a*2^e_offset) rounded as a float64. 'a' is modified */ +static uint64_t round_to_d(int *pe, mpb_t *a, int e_offset, int rnd_mode) +{ + int e; + uint64_t m; + + if (a->tab[0] == 0 && a->len == 1) { + /* zero result */ + m = 0; + e = 0; /* don't care */ + } else { + int prec, prec1, e_min; + e = mpb_floor_log2(a) + 1 - e_offset; + prec1 = 53; + e_min = -1021; + if (e < e_min) { + /* subnormal result or zero */ + prec = prec1 - (e_min - e); + } else { + prec = prec1; + } + mpb_shr_round(a, e + e_offset - prec, rnd_mode); + m = mpb_get_u64(a); + m <<= (53 - prec); + /* mantissa overflow due to rounding */ + if (m >= (uint64_t)1 << 53) { + m >>= 1; + e++; + } + } + *pe = e; + return m; +} + +/* return (m, e) such that m*2^(e-53) = round(a * radix^f) with 2^52 + <= m < 2^53 or m = 0. + 'a' is modified. */ +static uint64_t mul_pow_round_to_d(int *pe, mpb_t *a, + int radix1, int radix_shift, int f, int rnd_mode) +{ + int e_offset; + + e_offset = mul_pow(a, radix1, radix_shift, f, false, 55); + return round_to_d(pe, a, e_offset, rnd_mode); +} + +#ifdef JS_DTOA_DUMP_STATS +static int out_len_count[17]; + +void js_dtoa_dump_stats(void) +{ + int i, sum; + sum = 0; + for(i = 0; i < 17; i++) + sum += out_len_count[i]; + for(i = 0; i < 17; i++) { + printf("%2d %8d %5.2f%%\n", + i + 1, out_len_count[i], (double)out_len_count[i] / sum * 100); + } +} +#endif + +/* return a maximum bound of the string length. The bound depends on + 'd' only if format = JS_DTOA_FORMAT_FRAC or if JS_DTOA_EXP_DISABLED + is enabled. */ +int js_dtoa_max_len(double d, int radix, int n_digits, int flags) +{ + int fmt = flags & JS_DTOA_FORMAT_MASK; + int n, e; + uint64_t a; + + if (fmt != JS_DTOA_FORMAT_FRAC) { + if (fmt == JS_DTOA_FORMAT_FREE) { + n = dtoa_max_digits_table[radix - 2]; + } else { + n = n_digits; + } + if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_DISABLED) { + /* no exponential */ + a = float64_as_uint64(d); + e = (a >> 52) & 0x7ff; + if (e == 0x7ff) { + /* NaN, Infinity */ + n = 0; + } else { + e -= 1023; + /* XXX: adjust */ + n += 10 + abs(mul_log2_radix(e - 1, radix)); + } + } else { + /* extra: sign, 1 dot and exponent "e-1000" */ + n += 1 + 1 + 6; + } + } else { + a = float64_as_uint64(d); + e = (a >> 52) & 0x7ff; + if (e == 0x7ff) { + /* NaN, Infinity */ + n = 0; + } else { + /* high bound for the integer part */ + e -= 1023; + /* x < 2^(e + 1) */ + if (e < 0) { + n = 1; + } else { + n = 2 + mul_log2_radix(e - 1, radix); + } + /* sign, extra digit, 1 dot */ + n += 1 + 1 + 1 + n_digits; + } + } + return max_int(n, 9); /* also include NaN and [-]Infinity */ +} + +#if defined(__SANITIZE_ADDRESS__) && 0 +static void *dtoa_malloc(uint64_t **pptr, size_t size) +{ + return malloc(size); +} +static void dtoa_free(void *ptr) +{ + free(ptr); +} +#else +static void *dtoa_malloc(uint64_t **pptr, size_t size) +{ + void *ret; + ret = *pptr; + *pptr += (size + 7) / 8; + return ret; +} + +static void dtoa_free(void *ptr) +{ +} +#endif + +/* return the length */ +int js_dtoa(char *buf, double d, int radix, int n_digits, int flags, + JSDTOATempMem *tmp_mem) +{ + uint64_t a, m, *mptr = tmp_mem->mem; + int e, sgn, l, E, P, i, E_max, radix1, radix_shift; + char *q; + mpb_t *tmp1, *mant_max; + int fmt = flags & JS_DTOA_FORMAT_MASK; + + tmp1 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX); + mant_max = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * MANT_LEN_MAX); + assert((mptr - tmp_mem->mem) <= sizeof(JSDTOATempMem) / sizeof(mptr[0])); + + radix_shift = ctz32(radix); + radix1 = radix >> radix_shift; + a = float64_as_uint64(d); + sgn = a >> 63; + e = (a >> 52) & 0x7ff; + m = a & (((uint64_t)1 << 52) - 1); + q = buf; + if (e == 0x7ff) { + if (m == 0) { + if (sgn) + *q++ = '-'; + memcpy(q, "Infinity", 8); + q += 8; + } else { + memcpy(q, "NaN", 3); + q += 3; + } + goto done; + } else if (e == 0) { + if (m == 0) { + tmp1->len = 1; + tmp1->tab[0] = 0; + E = 1; + if (fmt == JS_DTOA_FORMAT_FREE) + P = 1; + else if (fmt == JS_DTOA_FORMAT_FRAC) + P = n_digits + 1; + else + P = n_digits; + /* "-0" is displayed as "0" if JS_DTOA_MINUS_ZERO is not present */ + if (sgn && (flags & JS_DTOA_MINUS_ZERO)) + *q++ = '-'; + goto output; + } + /* denormal number: convert to a normal number */ + l = clz64(m) - 11; + e -= l - 1; + m <<= l; + } else { + m |= (uint64_t)1 << 52; + } + if (sgn) + *q++ = '-'; + /* remove the bias */ + e -= 1022; + /* d = 2^(e-53)*m */ + // printf("m=0x%016" PRIx64 " e=%d\n", m, e); +#ifdef USE_FAST_INT + if (fmt == JS_DTOA_FORMAT_FREE && + e >= 1 && e <= 53 && + (m & (((uint64_t)1 << (53 - e)) - 1)) == 0 && + (flags & JS_DTOA_EXP_MASK) != JS_DTOA_EXP_ENABLED) { + m >>= 53 - e; + /* 'm' is never zero */ + q += u64toa_radix(q, m, radix); + goto done; + } +#endif + + /* this choice of E implies F=round(x*B^(P-E) is such as: + B^(P-1) <= F < 2.B^P. */ + E = 1 + mul_log2_radix(e - 1, radix); + + if (fmt == JS_DTOA_FORMAT_FREE) { + int P_max, E0, e1, E_found, P_found; + uint64_t m1, mant_found, mant, mant_max1; + /* P_max is guarranteed to work by construction */ + P_max = dtoa_max_digits_table[radix - 2]; + E0 = E; + E_found = 0; + P_found = 0; + mant_found = 0; + /* find the minimum number of digits by successive tries */ + P = P_max; /* P_max is guarateed to work */ + for(;;) { + /* mant_max always fits on 64 bits */ + mant_max1 = pow_ui(radix, P); + /* compute the mantissa in base B */ + E = E0; + for(;;) { + /* XXX: add inexact flag */ + mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDN); + mant = mpb_get_u64(tmp1); + if (mant < mant_max1) + break; + E++; /* at most one iteration is possible */ + } + /* remove useless trailing zero digits */ + while ((mant % radix) == 0) { + mant /= radix; + P--; + } + /* garanteed to work for P = P_max */ + if (P_found == 0) + goto prec_found; + /* convert back to base 2 */ + mpb_set_u64(tmp1, mant); + m1 = mul_pow_round_to_d(&e1, tmp1, radix1, radix_shift, E - P, JS_RNDN); + // printf("P=%2d: m=0x%016" PRIx64 " e=%d m1=0x%016" PRIx64 " e1=%d\n", P, m, e, m1, e1); + /* Note: (m, e) is never zero here, so the exponent for m1 + = 0 does not matter */ + if (m1 == m && e1 == e) { + prec_found: + P_found = P; + E_found = E; + mant_found = mant; + if (P == 1) + break; + P--; /* try lower exponent */ + } else { + break; + } + } + P = P_found; + E = E_found; + mpb_set_u64(tmp1, mant_found); +#ifdef JS_DTOA_DUMP_STATS + if (radix == 10) { + out_len_count[P - 1]++; + } +#endif + } else if (fmt == JS_DTOA_FORMAT_FRAC) { + int len; + + assert(n_digits >= 0 && n_digits <= JS_DTOA_MAX_DIGITS); + /* P = max_int(E, 1) + n_digits; */ + /* frac is rounded using RNDNA */ + mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, n_digits, JS_RNDNA); + + /* we add one extra digit on the left and remove it if needed + to avoid testing if the result is < radix^P */ + len = output_digits(q, tmp1, radix, max_int(E + 1, 1) + n_digits, + max_int(E + 1, 1)); + if (q[0] == '0' && len >= 2 && q[1] != '.') { + len--; + memmove(q, q + 1, len); + } + q += len; + goto done; + } else { + int pow_shift; + assert(n_digits >= 1 && n_digits <= JS_DTOA_MAX_DIGITS); + P = n_digits; + /* mant_max = radix^P */ + mant_max->len = 1; + mant_max->tab[0] = 1; + pow_shift = mul_pow(mant_max, radix1, radix_shift, P, false, 0); + mpb_shr_round(mant_max, pow_shift, JS_RNDZ); + + for(;;) { + /* fixed and frac are rounded using RNDNA */ + mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDNA); + if (mpb_cmp(tmp1, mant_max) < 0) + break; + E++; /* at most one iteration is possible */ + } + } + output: + if (fmt == JS_DTOA_FORMAT_FIXED) + E_max = n_digits; + else + E_max = dtoa_max_digits_table[radix - 2] + 4; + if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_ENABLED || + ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_AUTO && (E <= -6 || E > E_max))) { + q += output_digits(q, tmp1, radix, P, 1); + E--; + if (radix == 10) { + *q++ = 'e'; + } else if (radix1 == 1 && radix_shift <= 4) { + E *= radix_shift; + *q++ = 'p'; + } else { + *q++ = '@'; + } + if (E < 0) { + *q++ = '-'; + E = -E; + } else { + *q++ = '+'; + } + q += u32toa(q, E); + } else if (E <= 0) { + *q++ = '0'; + *q++ = '.'; + for(i = 0; i < -E; i++) + *q++ = '0'; + q += output_digits(q, tmp1, radix, P, P); + } else { + q += output_digits(q, tmp1, radix, P, min_int(P, E)); + for(i = 0; i < E - P; i++) + *q++ = '0'; + } + done: + *q = '\0'; + dtoa_free(mant_max); + dtoa_free(tmp1); + return q - buf; +} + +static inline int to_digit(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'z') + return c - 'a' + 10; + else + return 36; +} + +/* r = r * radix_base + a. radix_base = 0 means radix_base = 2^32 */ +static void mpb_mul1_base(mpb_t *r, limb_t radix_base, limb_t a) +{ + int i; + if (r->tab[0] == 0 && r->len == 1) { + r->tab[0] = a; + } else { + if (radix_base == 0) { + for(i = r->len; i >= 0; i--) { + r->tab[i + 1] = r->tab[i]; + } + r->tab[0] = a; + } else { + r->tab[r->len] = mp_mul1(r->tab, r->tab, r->len, + radix_base, a); + } + r->len++; + mpb_renorm(r); + } +} + +/* XXX: add fast path for small integers */ +double js_atod(const char *str, const char **pnext, int radix, int flags, + JSATODTempMem *tmp_mem) +{ + uint64_t *mptr = tmp_mem->mem; + const char *p, *p_start; + limb_t cur_limb, radix_base, extra_digits; + int is_neg, digit_count, limb_digit_count, digits_per_limb, sep, radix1, radix_shift; + int radix_bits, expn, e, max_digits, expn_offset, dot_pos, sig_pos, pos; + mpb_t *tmp0; + double dval; + bool is_bin_exp, is_zero, expn_overflow; + uint64_t m, a; + + tmp0 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX); + assert((mptr - tmp_mem->mem) <= sizeof(JSATODTempMem) / sizeof(mptr[0])); + /* optional separator between digits */ + sep = (flags & JS_ATOD_ACCEPT_UNDERSCORES) ? '_' : 256; + + p = str; + is_neg = 0; + if (p[0] == '+') { + p++; + p_start = p; + } else if (p[0] == '-') { + is_neg = 1; + p++; + p_start = p; + } else { + p_start = p; + } + + if (p[0] == '0') { + if ((p[1] == 'x' || p[1] == 'X') && + (radix == 0 || radix == 16)) { + p += 2; + radix = 16; + } else if ((p[1] == 'o' || p[1] == 'O') && + radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) { + p += 2; + radix = 8; + } else if ((p[1] == 'b' || p[1] == 'B') && + radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) { + p += 2; + radix = 2; + } else if ((p[1] >= '0' && p[1] <= '9') && + radix == 0 && (flags & JS_ATOD_ACCEPT_LEGACY_OCTAL)) { + int i; + sep = 256; + for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++) + continue; + if (p[i] == '8' || p[i] == '9') + goto no_prefix; + p += 1; + radix = 8; + } else { + goto no_prefix; + } + /* there must be a digit after the prefix */ + if (to_digit((uint8_t)*p) >= radix) + goto fail; + no_prefix: ; + } else { + if (!(flags & JS_ATOD_INT_ONLY) && js__strstart(p, "Infinity", &p)) + goto overflow; + } + if (radix == 0) + radix = 10; + + cur_limb = 0; + expn_offset = 0; + digit_count = 0; + limb_digit_count = 0; + max_digits = atod_max_digits_table[radix - 2]; + digits_per_limb = digits_per_limb_table[radix - 2]; + radix_base = radix_base_table[radix - 2]; + radix_shift = ctz32(radix); + radix1 = radix >> radix_shift; + if (radix1 == 1) { + /* radix = 2^radix_bits */ + radix_bits = radix_shift; + } else { + radix_bits = 0; + } + tmp0->len = 1; + tmp0->tab[0] = 0; + extra_digits = 0; + pos = 0; + dot_pos = -1; + /* skip leading zeros */ + for(;;) { + if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) && + !(flags & JS_ATOD_INT_ONLY)) { + if (*p == sep) + goto fail; + if (dot_pos >= 0) + break; + dot_pos = pos; + p++; + } + if (*p == sep && p > p_start && p[1] == '0') + p++; + if (*p != '0') + break; + p++; + pos++; + } + + sig_pos = pos; + for(;;) { + limb_t c; + if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) && + !(flags & JS_ATOD_INT_ONLY)) { + if (*p == sep) + goto fail; + if (dot_pos >= 0) + break; + dot_pos = pos; + p++; + } + if (*p == sep && p > p_start && to_digit(p[1]) < radix) + p++; + c = to_digit(*p); + if (c >= radix) + break; + p++; + pos++; + if (digit_count < max_digits) { + /* XXX: could be faster when radix_bits != 0 */ + cur_limb = cur_limb * radix + c; + limb_digit_count++; + if (limb_digit_count == digits_per_limb) { + mpb_mul1_base(tmp0, radix_base, cur_limb); + cur_limb = 0; + limb_digit_count = 0; + } + digit_count++; + } else { + extra_digits |= c; + } + } + if (limb_digit_count != 0) { + mpb_mul1_base(tmp0, pow_ui(radix, limb_digit_count), cur_limb); + } + if (digit_count == 0) { + is_zero = true; + expn_offset = 0; + } else { + is_zero = false; + if (dot_pos < 0) + dot_pos = pos; + expn_offset = sig_pos + digit_count - dot_pos; + } + + /* Use the extra digits for rounding if the base is a power of + two. Otherwise they are just truncated. */ + if (radix_bits != 0 && extra_digits != 0) { + tmp0->tab[0] |= 1; + } + + /* parse the exponent, if any */ + expn = 0; + expn_overflow = false; + is_bin_exp = false; + if (!(flags & JS_ATOD_INT_ONLY) && + ((radix == 10 && (*p == 'e' || *p == 'E')) || + (radix != 10 && (*p == '@' || + (radix_bits >= 1 && radix_bits <= 4 && (*p == 'p' || *p == 'P'))))) && + p > p_start) { + bool exp_is_neg; + int c; + is_bin_exp = (*p == 'p' || *p == 'P'); + p++; + exp_is_neg = false; + if (*p == '+') { + p++; + } else if (*p == '-') { + exp_is_neg = true; + p++; + } + c = to_digit(*p); + if (c >= 10) + goto fail; /* XXX: could stop before the exponent part */ + expn = c; + p++; + for(;;) { + if (*p == sep && to_digit(p[1]) < 10) + p++; + c = to_digit(*p); + if (c >= 10) + break; + if (!expn_overflow) { + if (unlikely(expn > ((INT32_MAX - 2 - 9) / 10))) { + expn_overflow = true; + } else { + expn = expn * 10 + c; + } + } + p++; + } + if (exp_is_neg) + expn = -expn; + /* if zero result, the exponent can be arbitrarily large */ + if (!is_zero && expn_overflow) { + if (exp_is_neg) + a = 0; + else + a = (uint64_t)0x7ff << 52; /* infinity */ + goto done; + } + } + + if (p == p_start) + goto fail; + + if (is_zero) { + a = 0; + } else { + int expn1; + if (radix_bits != 0) { + if (!is_bin_exp) + expn *= radix_bits; + expn -= expn_offset * radix_bits; + expn1 = expn + digit_count * radix_bits; + if (expn1 >= 1024 + radix_bits) + goto overflow; + else if (expn1 <= -1075) + goto underflow; + m = round_to_d(&e, tmp0, -expn, JS_RNDN); + } else { + expn -= expn_offset; + expn1 = expn + digit_count; + if (expn1 >= max_exponent[radix - 2] + 1) + goto overflow; + else if (expn1 <= min_exponent[radix - 2]) + goto underflow; + m = mul_pow_round_to_d(&e, tmp0, radix1, radix_shift, expn, JS_RNDN); + } + if (m == 0) { + underflow: + a = 0; + } else if (e > 1024) { + overflow: + /* overflow */ + a = (uint64_t)0x7ff << 52; + } else if (e < -1073) { + /* underflow */ + /* XXX: check rounding */ + a = 0; + } else if (e < -1021) { + /* subnormal */ + a = m >> (-e - 1021); + } else { + a = ((uint64_t)(e + 1022) << 52) | (m & (((uint64_t)1 << 52) - 1)); + } + } + done: + a |= (uint64_t)is_neg << 63; + dval = uint64_as_float64(a); + done1: + if (pnext) + *pnext = p; + dtoa_free(tmp0); + return dval; + fail: + dval = NAN; + goto done1; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/dtoa.h b/host/cred-script/vendor/rquickjs-sys/quickjs/dtoa.h new file mode 100644 index 0000000..85be040 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/dtoa.h @@ -0,0 +1,87 @@ +/* + * Tiny float64 printing and parsing library + * + * Copyright (c) 2024 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef DTOA_H +#define DTOA_H + +//#define JS_DTOA_DUMP_STATS + +/* maximum number of digits for fixed and frac formats */ +#define JS_DTOA_MAX_DIGITS 101 + +/* radix != 10 is only supported with flags = JS_DTOA_FORMAT_FREE */ +/* use as many digits as necessary */ +#define JS_DTOA_FORMAT_FREE (0 << 0) +/* use n_digits significant digits (1 <= n_digits <= JS_DTOA_MAX_DIGITS) */ +#define JS_DTOA_FORMAT_FIXED (1 << 0) +/* force fractional format: [-]dd.dd with n_digits fractional digits. + 0 <= n_digits <= JS_DTOA_MAX_DIGITS */ +#define JS_DTOA_FORMAT_FRAC (2 << 0) +#define JS_DTOA_FORMAT_MASK (3 << 0) + +/* select exponential notation either in fixed or free format */ +#define JS_DTOA_EXP_AUTO (0 << 2) +#define JS_DTOA_EXP_ENABLED (1 << 2) +#define JS_DTOA_EXP_DISABLED (2 << 2) +#define JS_DTOA_EXP_MASK (3 << 2) + +#define JS_DTOA_MINUS_ZERO (1 << 4) /* show the minus sign for -0 */ + +/* only accepts integers (no dot, no exponent) */ +#define JS_ATOD_INT_ONLY (1 << 0) +/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */ +#define JS_ATOD_ACCEPT_BIN_OCT (1 << 1) +/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */ +#define JS_ATOD_ACCEPT_LEGACY_OCTAL (1 << 2) +/* accept _ between digits as a digit separator */ +#define JS_ATOD_ACCEPT_UNDERSCORES (1 << 3) + +typedef struct { + uint64_t mem[37]; +} JSDTOATempMem; + +typedef struct { + uint64_t mem[27]; +} JSATODTempMem; + +/* return a maximum bound of the string length */ +int js_dtoa_max_len(double d, int radix, int n_digits, int flags); +/* return the string length */ +int js_dtoa(char *buf, double d, int radix, int n_digits, int flags, + JSDTOATempMem *tmp_mem); +double js_atod(const char *str, const char **pnext, int radix, int flags, + JSATODTempMem *tmp_mem); + +#ifdef JS_DTOA_DUMP_STATS +void js_dtoa_dump_stats(void); +#endif + +/* additional exported functions */ +size_t u32toa(char *buf, uint32_t n); +size_t i32toa(char *buf, int32_t n); +size_t u64toa(char *buf, uint64_t n); +size_t i64toa(char *buf, int64_t n); +size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix); +size_t i64toa_radix(char *buf, int64_t n, unsigned int radix); + +#endif /* DTOA_H */ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/examples/fib.c b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/fib.c new file mode 100644 index 0000000..b965acc --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/fib.c @@ -0,0 +1,80 @@ +/* + * QuickJS: Example of C module + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "../quickjs.h" + +#define countof(x) (sizeof(x) / sizeof((x)[0])) + +static int fib(int n) +{ + if (n <= 0) + return 0; + else if (n == 1) + return 1; + else + return fib(n - 1) + fib(n - 2); +} + +static JSValue js_fib(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + int n, res; + if (JS_ToInt32(ctx, &n, argv[0])) + return JS_EXCEPTION; + res = fib(n); + return JS_NewInt32(ctx, res); +} + +static const JSCFunctionListEntry js_fib_funcs[] = { + JS_CFUNC_DEF("fib", 1, js_fib ), +}; + +static int js_fib_init(JSContext *ctx, JSModuleDef *m) +{ + return JS_SetModuleExportList(ctx, m, js_fib_funcs, + countof(js_fib_funcs)); +} + +#ifdef JS_SHARED_LIBRARY +#define JS_INIT_MODULE js_init_module +#else +#define JS_INIT_MODULE js_init_module_fib +#endif + +#ifndef JS_EXTERN +#ifdef _WIN32 +#define JS_EXTERN __declspec(dllexport) +#else +#define JS_EXTERN +#endif +#endif + +JS_EXTERN JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_fib_init); + if (!m) + return NULL; + JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs)); + return m; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/examples/fib_module.js b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/fib_module.js new file mode 100644 index 0000000..6a81071 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/fib_module.js @@ -0,0 +1,10 @@ +/* fib module */ +export function fib(n) +{ + if (n <= 0) + return 0; + else if (n == 1) + return 1; + else + return fib(n - 1) + fib(n - 2); +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/examples/hello.js b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/hello.js new file mode 100644 index 0000000..accefce --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/hello.js @@ -0,0 +1 @@ +console.log("Hello World"); diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/examples/hello_module.js b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/hello_module.js new file mode 100644 index 0000000..463660f --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/hello_module.js @@ -0,0 +1,6 @@ +/* example of JS module */ + +import { fib } from "./fib_module.js"; + +console.log("Hello World"); +console.log("fib(10)=", fib(10)); diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/examples/meson.build b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/meson.build new file mode 100644 index 0000000..08c9d87 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/meson.build @@ -0,0 +1,19 @@ +shared_module( + 'fib', + 'fib.c', + + name_prefix: '', + gnu_symbol_visibility: 'default', + c_args: ['-DJS_SHARED_LIBRARY'], + dependencies: host_system == 'windows' ? qjs_dep : [], +) + +shared_module( + 'point', + 'point.c', + + name_prefix: '', + gnu_symbol_visibility: 'default', + c_args: ['-DJS_SHARED_LIBRARY'], + dependencies: host_system == 'windows' ? qjs_dep : [], +) diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/examples/pi_bigint.js b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/pi_bigint.js new file mode 100644 index 0000000..e15abd1 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/pi_bigint.js @@ -0,0 +1,118 @@ +/* + * PI computation in Javascript using the BigInt type + */ +"use strict"; + +/* return floor(log2(a)) for a > 0 and 0 for a = 0 */ +function floor_log2(a) +{ + var k_max, a1, k, i; + k_max = 0n; + while ((a >> (2n ** k_max)) != 0n) { + k_max++; + } + k = 0n; + a1 = a; + for(i = k_max - 1n; i >= 0n; i--) { + a1 = a >> (2n ** i); + if (a1 != 0n) { + a = a1; + k |= (1n << i); + } + } + return k; +} + +/* return ceil(log2(a)) for a > 0 */ +function ceil_log2(a) +{ + return floor_log2(a - 1n) + 1n; +} + +/* return floor(sqrt(a)) (not efficient but simple) */ +function int_sqrt(a) +{ + var l, u, s; + if (a == 0n) + return a; + l = ceil_log2(a); + u = 1n << ((l + 1n) / 2n); + /* u >= floor(sqrt(a)) */ + for(;;) { + s = u; + u = ((a / s) + s) / 2n; + if (u >= s) + break; + } + return s; +} + +/* return pi * 2**prec */ +function calc_pi(prec) { + const CHUD_A = 13591409n; + const CHUD_B = 545140134n; + const CHUD_C = 640320n; + const CHUD_C3 = 10939058860032000n; /* C^3/24 */ + const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ + + /* return [P, Q, G] */ + function chud_bs(a, b, need_G) { + var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; + if (a == (b - 1n)) { + G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); + P = G * (CHUD_B * b + CHUD_A); + if (b & 1n) + P = -P; + Q = b * b * b * CHUD_C3; + } else { + c = (a + b) >> 1n; + [P1, Q1, G1] = chud_bs(a, c, true); + [P2, Q2, G2] = chud_bs(c, b, need_G); + P = P1 * Q2 + P2 * G1; + Q = Q1 * Q2; + if (need_G) + G = G1 * G2; + else + G = 0n; + } + return [P, Q, G]; + } + + var n, P, Q, G; + /* number of serie terms */ + n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n; + [P, Q, G] = chud_bs(0n, n, false); + Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A); + G = int_sqrt(CHUD_C << (2n * prec)); + return (Q * G) >> prec; +} + +function main(args) { + var r, n_digits, n_bits, out; + if (args.length < 1) { + print("usage: pi n_digits"); + return; + } + n_digits = args[0] | 0; + + /* we add more bits to reduce the probability of bad rounding for + the last digits */ + n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n; + r = calc_pi(n_bits); + r = ((10n ** BigInt(n_digits)) * r) >> n_bits; + out = r.toString(); + print(out[0] + "." + out.slice(1)); +} + +var args; +if (typeof scriptArgs != "undefined") { + args = scriptArgs; + args.shift(); +} else if (typeof arguments != "undefined") { + args = arguments; +} else { + /* default: 1000 digits */ + args=[1000]; +} + +main(args); diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/examples/point.c b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/point.c new file mode 100644 index 0000000..a82df15 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/point.c @@ -0,0 +1,160 @@ +/* + * QuickJS: Example of C module with a class + * + * Copyright (c) 2019 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "../quickjs.h" +#include + +#define countof(x) (sizeof(x) / sizeof((x)[0])) + +/* Point Class */ + +typedef struct { + int x; + int y; +} JSPointData; + +static JSClassID js_point_class_id; + +static void js_point_finalizer(JSRuntime *rt, JSValue val) +{ + JSPointData *s = JS_GetOpaque(val, js_point_class_id); + /* Note: 's' can be NULL in case JS_SetOpaque() was not called */ + js_free_rt(rt, s); +} + +static JSValue js_point_ctor(JSContext *ctx, + JSValue new_target, + int argc, JSValue *argv) +{ + JSPointData *s; + JSValue obj = JS_UNDEFINED; + JSValue proto; + + s = js_mallocz(ctx, sizeof(*s)); + if (!s) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &s->x, argv[0])) + goto fail; + if (JS_ToInt32(ctx, &s->y, argv[1])) + goto fail; + /* using new_target to get the prototype is necessary when the + class is extended. */ + proto = JS_GetPropertyStr(ctx, new_target, "prototype"); + if (JS_IsException(proto)) + goto fail; + obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id); + JS_FreeValue(ctx, proto); + if (JS_IsException(obj)) + goto fail; + JS_SetOpaque(obj, s); + return obj; + fail: + js_free(ctx, s); + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_point_get_xy(JSContext *ctx, JSValue this_val, int magic) +{ + JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); + if (!s) + return JS_EXCEPTION; + if (magic == 0) + return JS_NewInt32(ctx, s->x); + else + return JS_NewInt32(ctx, s->y); +} + +static JSValue js_point_set_xy(JSContext *ctx, JSValue this_val, JSValue val, int magic) +{ + JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); + int v; + if (!s) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &v, val)) + return JS_EXCEPTION; + if (magic == 0) + s->x = v; + else + s->y = v; + return JS_UNDEFINED; +} + +static JSValue js_point_norm(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); + if (!s) + return JS_EXCEPTION; + return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y)); +} + +static JSClassDef js_point_class = { + "Point", + .finalizer = js_point_finalizer, +}; + +static const JSCFunctionListEntry js_point_proto_funcs[] = { + JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0), + JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1), + JS_CFUNC_DEF("norm", 0, js_point_norm), +}; + +static int js_point_init(JSContext *ctx, JSModuleDef *m) +{ + JSValue point_proto, point_class; + JSRuntime *rt = JS_GetRuntime(ctx); + + /* create the Point class */ + JS_NewClassID(rt, &js_point_class_id); + JS_NewClass(rt, js_point_class_id, &js_point_class); + + point_proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs)); + + point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0); + /* set proto.constructor and ctor.prototype */ + JS_SetConstructor(ctx, point_class, point_proto); + JS_SetClassProto(ctx, js_point_class_id, point_proto); + + JS_SetModuleExport(ctx, m, "Point", point_class); + return 0; +} + +#ifndef JS_EXTERN +#ifdef _WIN32 +#define JS_EXTERN __declspec(dllexport) +#else +#define JS_EXTERN +#endif +#endif + +JS_EXTERN JSModuleDef *js_init_module(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_point_init); + if (!m) + return NULL; + JS_AddModuleExport(ctx, m, "Point"); + return m; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/examples/test_fib.js b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/test_fib.js new file mode 100644 index 0000000..f22c576 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/test_fib.js @@ -0,0 +1,8 @@ +/* example of JS module importing a C module */ +import * as os from "qjs:os"; + +const isWin = os.platform === 'win32'; +const { fib } = await import(`./fib.${isWin ? 'dll' : 'so'}`); + +console.log("Hello World"); +console.log("fib(10)=", fib(10)); diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/examples/test_point.js b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/test_point.js new file mode 100644 index 0000000..1e0fafa --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/examples/test_point.js @@ -0,0 +1,43 @@ +/* example of JS module importing a C module */ +import * as os from "qjs:os"; + +const isWin = os.platform === 'win32'; +const { Point } = await import(`./point.${isWin ? 'dll' : 'so'}`); + +function assert(b, str) +{ + if (b) { + return; + } else { + throw Error("assertion failed: " + str); + } +} + +class ColorPoint extends Point { + constructor(x, y, color) { + super(x, y); + this.color = color; + } + get_color() { + return this.color; + } +}; + +function main() +{ + var pt, pt2; + + pt = new Point(2, 3); + assert(pt.x === 2); + assert(pt.y === 3); + pt.x = 4; + assert(pt.x === 4); + assert(pt.norm() == 5); + + pt2 = new ColorPoint(2, 3, 0xffffff); + assert(pt2.x === 2); + assert(pt2.color === 0xffffff); + assert(pt2.get_color() === 0xffffff); +} + +main(); diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/fuzz.c b/host/cred-script/vendor/rquickjs-sys/quickjs/fuzz.c new file mode 100644 index 0000000..fca8fa4 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/fuzz.c @@ -0,0 +1,22 @@ +// clang -g -O1 -fsanitize=fuzzer -o fuzz fuzz.c +#include "quickjs.h" +#include "quickjs.c" +#include "cutils.c" +#include "libregexp.c" +#include "libunicode.c" +#include + +int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + JSRuntime *rt = JS_NewRuntime(); + if (!rt) + exit(1); + JSContext *ctx = JS_NewContext(rt); + if (!ctx) + exit(1); + JSValue val = JS_ReadObject(ctx, buf, len, /*flags*/0); + JS_FreeValue(ctx, val); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return 0; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/gen/function_source.c b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/function_source.c new file mode 100644 index 0000000..b518a78 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/function_source.c @@ -0,0 +1,80 @@ +/* File generated automatically by the QuickJS-ng compiler. */ + +#include "quickjs-libc.h" + +const uint32_t qjsc_function_source_size = 324; + +const uint8_t qjsc_function_source[324] = { + 0x15, 0x05, 0x01, 0x30, 0x74, 0x65, 0x73, 0x74, + 0x73, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x6a, 0x73, 0x01, 0x0c, 0x61, 0x63, + 0x74, 0x75, 0x61, 0x6c, 0x01, 0x02, 0x66, 0x01, + 0x0c, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x01, + 0x34, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x66, 0x28, 0x29, 0x20, 0x7b, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x34, + 0x32, 0x20, 0x7d, 0x0d, 0xc6, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x20, 0x0a, 0x01, 0xa2, + 0x01, 0x00, 0x05, 0x00, 0x03, 0x02, 0x01, 0x74, + 0x05, 0xc8, 0x03, 0x02, 0x00, 0x30, 0xca, 0x03, + 0x04, 0x00, 0x70, 0xc8, 0x03, 0x04, 0x02, 0x70, + 0x10, 0x00, 0x01, 0x00, 0xe4, 0x01, 0x00, 0x01, + 0x00, 0xcc, 0x03, 0x00, 0x0d, 0xca, 0x03, 0x01, + 0x01, 0x0c, 0x43, 0x0a, 0x01, 0xca, 0x03, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0xbe, + 0x2a, 0x28, 0xc6, 0x03, 0x03, 0x01, 0x00, 0x1a, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x66, 0x28, 0x29, 0x20, 0x7b, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x34, 0x32, + 0x20, 0x7d, 0x0c, 0x03, 0xc4, 0x04, 0x08, 0xce, + 0x08, 0xec, 0x05, 0xc1, 0x00, 0xe4, 0x29, 0x04, + 0xe7, 0x00, 0x00, 0x00, 0xe3, 0x62, 0x00, 0x00, + 0xe0, 0x43, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0xcb, 0x63, 0x00, 0x00, 0x66, 0x00, 0x00, + 0xb0, 0xec, 0x0b, 0x39, 0x96, 0x00, 0x00, 0x00, + 0x63, 0x00, 0x00, 0xf1, 0x30, 0x62, 0x02, 0x00, + 0x62, 0x01, 0x00, 0x39, 0x3b, 0x00, 0x00, 0x00, + 0x66, 0x00, 0x00, 0x04, 0xe5, 0x00, 0x00, 0x00, + 0x9e, 0x32, 0x01, 0x00, 0x03, 0x00, 0xcc, 0x63, + 0x01, 0x00, 0x43, 0x38, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0xcd, 0x63, 0x02, 0x00, 0x66, 0x00, + 0x00, 0xb0, 0xec, 0x0b, 0x39, 0x96, 0x00, 0x00, + 0x00, 0x63, 0x02, 0x00, 0xf1, 0x30, 0x69, 0x02, + 0x00, 0x69, 0x01, 0x00, 0x06, 0x2f, 0xc6, 0x03, + 0x01, 0x01, 0x18, 0x00, 0x1c, 0x0a, 0x2a, 0x26, + 0x03, 0x20, 0x1c, 0x1b, 0x0c, 0x00, 0x10, 0x08, + 0x27, 0x11, 0x12, 0x67, 0x0d, 0x26, 0x03, 0x20, + 0x1c, 0x1b, 0x0c, 0x00, +}; + +static JSContext *JS_NewCustomContext(JSRuntime *rt) +{ + JSContext *ctx = JS_NewContext(rt); + if (!ctx) + return NULL; + return ctx; +} + +int main(int argc, char **argv) +{ + int r; + JSRuntime *rt; + JSContext *ctx; + r = 0; + rt = JS_NewRuntime(); + js_std_set_worker_new_context_func(JS_NewCustomContext); + js_std_init_handlers(rt); + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); + ctx = JS_NewCustomContext(rt); + js_std_add_helpers(ctx, argc, argv); + js_std_eval_binary(ctx, qjsc_function_source, qjsc_function_source_size, 0); + r = js_std_loop(ctx); + if (r) { + js_std_dump_error(ctx); + } + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return r; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/gen/hello.c b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/hello.c new file mode 100644 index 0000000..27dcd5d --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/hello.c @@ -0,0 +1,52 @@ +/* File generated automatically by the QuickJS-ng compiler. */ + +#include "quickjs-libc.h" + +const uint32_t qjsc_hello_size = 103; + +const uint8_t qjsc_hello[103] = { + 0x15, 0x04, 0x01, 0x22, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, + 0x6c, 0x6f, 0x2e, 0x6a, 0x73, 0x01, 0x0e, 0x63, + 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x01, 0x06, + 0x6c, 0x6f, 0x67, 0x01, 0x16, 0x48, 0x65, 0x6c, + 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, + 0x0d, 0xc6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x20, 0x0a, 0x01, 0xa2, 0x01, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x19, 0x00, 0x08, 0xec, + 0x02, 0x29, 0x39, 0xe4, 0x00, 0x00, 0x00, 0x43, + 0xe5, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0x06, 0x2f, 0xc6, + 0x03, 0x01, 0x01, 0x02, 0x48, 0x0e, 0x00, +}; + +static JSContext *JS_NewCustomContext(JSRuntime *rt) +{ + JSContext *ctx = JS_NewContext(rt); + if (!ctx) + return NULL; + return ctx; +} + +int main(int argc, char **argv) +{ + int r; + JSRuntime *rt; + JSContext *ctx; + r = 0; + rt = JS_NewRuntime(); + js_std_set_worker_new_context_func(JS_NewCustomContext); + js_std_init_handlers(rt); + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); + ctx = JS_NewCustomContext(rt); + js_std_add_helpers(ctx, argc, argv); + js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0); + r = js_std_loop(ctx); + if (r) { + js_std_dump_error(ctx); + } + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return r; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/gen/hello_module.c b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/hello_module.c new file mode 100644 index 0000000..2eb98fc --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/hello_module.c @@ -0,0 +1,106 @@ +/* File generated automatically by the QuickJS-ng compiler. */ + +#include "quickjs-libc.h" + +const uint32_t qjsc_fib_module_size = 290; + +const uint8_t qjsc_fib_module[290] = { + 0x15, 0x03, 0x01, 0x2c, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x62, + 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, + 0x6a, 0x73, 0x01, 0x06, 0x66, 0x69, 0x62, 0x01, + 0x02, 0x6e, 0x0d, 0xc6, 0x03, 0x00, 0x01, 0x00, + 0x00, 0xc8, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x20, + 0x0a, 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x09, 0x00, 0xc8, 0x03, 0x00, 0x01, + 0x0c, 0x43, 0x0a, 0x01, 0xc8, 0x03, 0x01, 0x00, + 0x01, 0x04, 0x01, 0x00, 0x1a, 0x01, 0xca, 0x03, + 0x00, 0x01, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xd3, + 0xb6, 0xa8, 0xec, 0x03, 0xb6, 0x28, 0xd3, 0xb7, + 0xad, 0xec, 0x03, 0xb7, 0x28, 0xdf, 0xd3, 0xb7, + 0x9f, 0xf1, 0xdf, 0xd3, 0xb8, 0x9f, 0xf1, 0x9e, + 0x28, 0xc6, 0x03, 0x02, 0x08, 0x0e, 0x09, 0x0c, + 0x27, 0x0a, 0x28, 0x02, 0x07, 0x08, 0x11, 0x0a, + 0x07, 0x08, 0x07, 0x08, 0x8d, 0x01, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, + 0x69, 0x62, 0x28, 0x6e, 0x29, 0x0a, 0x7b, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x6e, 0x20, 0x3c, 0x3d, 0x20, 0x30, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, + 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, + 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x29, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x3b, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, + 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x66, 0x69, 0x62, 0x28, 0x6e, 0x20, 0x2d, + 0x20, 0x31, 0x29, 0x20, 0x2b, 0x20, 0x66, 0x69, + 0x62, 0x28, 0x6e, 0x20, 0x2d, 0x20, 0x32, 0x29, + 0x3b, 0x0a, 0x7d, 0x08, 0xec, 0x05, 0xc1, 0x00, + 0xe3, 0x29, 0x06, 0x2f, 0xc6, 0x03, 0x01, 0x01, + 0x00, 0x00, +}; + +const uint32_t qjsc_hello_module_size = 187; + +const uint8_t qjsc_hello_module[187] = { + 0x15, 0x07, 0x01, 0x30, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, + 0x6c, 0x6f, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x2e, 0x6a, 0x73, 0x01, 0x1e, 0x2e, 0x2f, + 0x66, 0x69, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x75, + 0x6c, 0x65, 0x2e, 0x6a, 0x73, 0x01, 0x06, 0x66, + 0x69, 0x62, 0x01, 0x0e, 0x63, 0x6f, 0x6e, 0x73, + 0x6f, 0x6c, 0x65, 0x01, 0x06, 0x6c, 0x6f, 0x67, + 0x01, 0x16, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, + 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x01, 0x10, 0x66, + 0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, + 0xc6, 0x03, 0x01, 0xc8, 0x03, 0x00, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x00, 0x00, 0x0c, 0x20, 0x0a, + 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x05, 0x01, + 0x00, 0x32, 0x00, 0xca, 0x03, 0x00, 0x0c, 0x08, + 0xec, 0x02, 0x29, 0x39, 0xe6, 0x00, 0x00, 0x00, + 0x43, 0xe7, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x39, 0xe6, + 0x00, 0x00, 0x00, 0x43, 0xe7, 0x00, 0x00, 0x00, + 0x04, 0xe9, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, + 0xbe, 0x0a, 0xf1, 0x24, 0x02, 0x00, 0x0e, 0x06, + 0x2f, 0xc6, 0x03, 0x01, 0x01, 0x0c, 0x00, 0x04, + 0x08, 0x00, 0x34, 0x10, 0x30, 0x0f, 0x34, 0x10, + 0x2a, 0x20, 0x00, +}; + +static JSContext *JS_NewCustomContext(JSRuntime *rt) +{ + JSContext *ctx = JS_NewContext(rt); + if (!ctx) + return NULL; + js_std_eval_binary(ctx, qjsc_fib_module, qjsc_fib_module_size, 1); + return ctx; +} + +int main(int argc, char **argv) +{ + int r; + JSRuntime *rt; + JSContext *ctx; + r = 0; + rt = JS_NewRuntime(); + js_std_set_worker_new_context_func(JS_NewCustomContext); + js_std_init_handlers(rt); + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); + ctx = JS_NewCustomContext(rt); + js_std_add_helpers(ctx, argc, argv); + js_std_eval_binary(ctx, qjsc_hello_module, qjsc_hello_module_size, 0); + r = js_std_loop(ctx); + if (r) { + js_std_dump_error(ctx); + } + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return r; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/gen/repl.c b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/repl.c new file mode 100644 index 0000000..0a4e66d --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/repl.c @@ -0,0 +1,3025 @@ +/* File generated automatically by the QuickJS-ng compiler. */ + +#include + +const uint32_t qjsc_repl_size = 24126; + +const uint8_t qjsc_repl[24126] = { + 0x15, 0xb6, 0x04, 0x01, 0x0e, 0x72, 0x65, 0x70, + 0x6c, 0x2e, 0x6a, 0x73, 0x01, 0x0e, 0x71, 0x6a, + 0x73, 0x3a, 0x73, 0x74, 0x64, 0x01, 0x0c, 0x71, + 0x6a, 0x73, 0x3a, 0x6f, 0x73, 0x01, 0x12, 0x71, + 0x6a, 0x73, 0x3a, 0x62, 0x6a, 0x73, 0x6f, 0x6e, + 0x01, 0x06, 0x73, 0x74, 0x64, 0x01, 0x04, 0x6f, + 0x73, 0x01, 0x0a, 0x62, 0x6a, 0x73, 0x6f, 0x6e, + 0x01, 0x02, 0x67, 0x01, 0x10, 0x69, 0x73, 0x46, + 0x69, 0x6e, 0x69, 0x74, 0x65, 0x01, 0x0a, 0x69, + 0x73, 0x4e, 0x61, 0x4e, 0x01, 0x10, 0x49, 0x6e, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x01, 0x0e, + 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x01, + 0x10, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, + 0x73, 0x01, 0x0c, 0x63, 0x6f, 0x6c, 0x6f, 0x72, + 0x73, 0x01, 0x0c, 0x74, 0x68, 0x65, 0x6d, 0x65, + 0x73, 0x01, 0x0c, 0x73, 0x74, 0x79, 0x6c, 0x65, + 0x73, 0x01, 0x08, 0x75, 0x74, 0x66, 0x38, 0x01, + 0x12, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x01, 0x16, 0x73, 0x68, 0x6f, 0x77, + 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x01, + 0x16, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x68, 0x69, + 0x64, 0x64, 0x65, 0x6e, 0x01, 0x14, 0x73, 0x68, + 0x6f, 0x77, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, + 0x01, 0x10, 0x68, 0x65, 0x78, 0x5f, 0x6d, 0x6f, + 0x64, 0x65, 0x01, 0x14, 0x75, 0x73, 0x65, 0x5f, + 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x01, 0x0e, + 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x01, + 0x1a, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x01, 0x14, + 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x01, 0x0c, 0x70, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x01, 0x0c, 0x70, 0x72, 0x6f, 0x6d, + 0x70, 0x74, 0x01, 0x08, 0x70, 0x6c, 0x65, 0x6e, + 0x01, 0x06, 0x70, 0x73, 0x31, 0x01, 0x06, 0x70, + 0x73, 0x32, 0x01, 0x1e, 0x65, 0x76, 0x61, 0x6c, + 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x01, 0x12, 0x65, 0x76, 0x61, + 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x01, 0x0a, + 0x6d, 0x65, 0x78, 0x70, 0x72, 0x01, 0x0a, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x01, 0x06, 0x63, 0x6d, + 0x64, 0x01, 0x14, 0x63, 0x75, 0x72, 0x73, 0x6f, + 0x72, 0x5f, 0x70, 0x6f, 0x73, 0x01, 0x10, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6d, 0x64, 0x01, + 0x1e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x75, + 0x72, 0x73, 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x73, + 0x01, 0x10, 0x74, 0x68, 0x69, 0x73, 0x5f, 0x66, + 0x75, 0x6e, 0x01, 0x10, 0x6c, 0x61, 0x73, 0x74, + 0x5f, 0x66, 0x75, 0x6e, 0x01, 0x14, 0x71, 0x75, + 0x6f, 0x74, 0x65, 0x5f, 0x66, 0x6c, 0x61, 0x67, + 0x01, 0x14, 0x75, 0x74, 0x66, 0x38, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x01, 0x10, 0x75, 0x74, + 0x66, 0x38, 0x5f, 0x76, 0x61, 0x6c, 0x01, 0x0e, + 0x74, 0x65, 0x72, 0x6d, 0x5f, 0x66, 0x64, 0x01, + 0x1a, 0x74, 0x65, 0x72, 0x6d, 0x5f, 0x72, 0x65, + 0x61, 0x64, 0x5f, 0x62, 0x75, 0x66, 0x01, 0x14, + 0x74, 0x65, 0x72, 0x6d, 0x5f, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x01, 0x1a, 0x74, 0x65, 0x72, 0x6d, + 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x5f, + 0x78, 0x01, 0x10, 0x74, 0x65, 0x72, 0x6d, 0x49, + 0x6e, 0x69, 0x74, 0x01, 0x1c, 0x73, 0x69, 0x67, + 0x69, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x72, 0x01, 0x22, 0x74, 0x65, 0x72, + 0x6d, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x68, + 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x01, 0x16, + 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x62, + 0x79, 0x74, 0x65, 0x01, 0x10, 0x69, 0x73, 0x5f, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x01, 0x10, 0x69, + 0x73, 0x5f, 0x64, 0x69, 0x67, 0x69, 0x74, 0x01, + 0x0e, 0x69, 0x73, 0x5f, 0x77, 0x6f, 0x72, 0x64, + 0x01, 0x10, 0x69, 0x73, 0x5f, 0x62, 0x6c, 0x61, + 0x6e, 0x6b, 0x01, 0x14, 0x75, 0x63, 0x73, 0x5f, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x01, 0x2a, + 0x69, 0x73, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6c, + 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x75, 0x72, 0x72, + 0x6f, 0x67, 0x61, 0x74, 0x65, 0x01, 0x16, 0x69, + 0x73, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x64, 0x01, 0x20, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, + 0x74, 0x65, 0x78, 0x74, 0x01, 0x12, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x5f, 0x63, 0x73, 0x69, 0x01, + 0x16, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x63, 0x75, + 0x72, 0x73, 0x6f, 0x72, 0x01, 0x0c, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x01, 0x0c, 0x69, 0x6e, + 0x73, 0x65, 0x72, 0x74, 0x01, 0x1a, 0x71, 0x75, + 0x6f, 0x74, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x73, + 0x65, 0x72, 0x74, 0x01, 0x0a, 0x61, 0x62, 0x6f, + 0x72, 0x74, 0x01, 0x0a, 0x61, 0x6c, 0x65, 0x72, + 0x74, 0x01, 0x22, 0x62, 0x65, 0x67, 0x69, 0x6e, + 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x66, 0x5f, + 0x6c, 0x69, 0x6e, 0x65, 0x01, 0x16, 0x65, 0x6e, + 0x64, 0x5f, 0x6f, 0x66, 0x5f, 0x6c, 0x69, 0x6e, + 0x65, 0x01, 0x18, 0x66, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x01, + 0x1a, 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, + 0x64, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x01, 0x22, + 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x77, 0x6f, 0x72, + 0x64, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x01, 0x24, 0x73, 0x6b, 0x69, 0x70, 0x5f, + 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x62, 0x61, 0x63, + 0x6b, 0x77, 0x61, 0x72, 0x64, 0x01, 0x18, 0x66, + 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x77, + 0x6f, 0x72, 0x64, 0x01, 0x1a, 0x62, 0x61, 0x63, + 0x6b, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x77, 0x6f, + 0x72, 0x64, 0x01, 0x18, 0x63, 0x6c, 0x65, 0x61, + 0x72, 0x5f, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, + 0x01, 0x16, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x01, 0x16, 0x68, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x61, + 0x64, 0x64, 0x01, 0x20, 0x70, 0x72, 0x65, 0x76, + 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x01, 0x18, 0x6e, 0x65, + 0x78, 0x74, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x01, 0x1c, 0x68, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x01, 0x2e, 0x68, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x77, + 0x61, 0x72, 0x64, 0x01, 0x2c, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x5f, 0x66, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x01, 0x1e, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x72, + 0x5f, 0x64, 0x69, 0x72, 0x01, 0x16, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, + 0x72, 0x01, 0x12, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x5f, 0x64, 0x01, 0x28, 0x62, 0x61, + 0x63, 0x6b, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x63, 0x68, + 0x61, 0x72, 0x01, 0x1e, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x70, 0x6f, 0x73, 0x65, 0x5f, 0x63, 0x68, + 0x61, 0x72, 0x73, 0x01, 0x1e, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x5f, 0x77, + 0x6f, 0x72, 0x64, 0x73, 0x01, 0x16, 0x75, 0x70, + 0x63, 0x61, 0x73, 0x65, 0x5f, 0x77, 0x6f, 0x72, + 0x64, 0x01, 0x1a, 0x64, 0x6f, 0x77, 0x6e, 0x63, + 0x61, 0x73, 0x65, 0x5f, 0x77, 0x6f, 0x72, 0x64, + 0x01, 0x16, 0x6b, 0x69, 0x6c, 0x6c, 0x5f, 0x72, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x01, 0x12, 0x6b, + 0x69, 0x6c, 0x6c, 0x5f, 0x6c, 0x69, 0x6e, 0x65, + 0x01, 0x24, 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, + 0x72, 0x64, 0x5f, 0x6b, 0x69, 0x6c, 0x6c, 0x5f, + 0x6c, 0x69, 0x6e, 0x65, 0x01, 0x12, 0x6b, 0x69, + 0x6c, 0x6c, 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x01, + 0x24, 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, + 0x64, 0x5f, 0x6b, 0x69, 0x6c, 0x6c, 0x5f, 0x77, + 0x6f, 0x72, 0x64, 0x01, 0x08, 0x79, 0x61, 0x6e, + 0x6b, 0x01, 0x12, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x5f, 0x63, 0x01, 0x0a, 0x72, 0x65, + 0x73, 0x65, 0x74, 0x01, 0x22, 0x69, 0x73, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x70, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x01, 0x20, + 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x5f, 0x77, 0x6f, 0x72, 0x64, + 0x01, 0x24, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x01, 0x1e, 0x67, 0x65, + 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x01, 0x14, 0x63, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, + 0x6e, 0x01, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x73, 0x01, 0x0c, 0x64, 0x75, 0x70, + 0x73, 0x74, 0x72, 0x01, 0x1a, 0x72, 0x65, 0x61, + 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6b, 0x65, + 0x79, 0x73, 0x01, 0x1c, 0x72, 0x65, 0x61, 0x64, + 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x01, 0x16, 0x72, 0x65, 0x61, 0x64, + 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x62, 0x01, + 0x2a, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, + 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x5f, + 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x01, 0x1c, + 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, + 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x01, 0x16, + 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x63, + 0x68, 0x61, 0x72, 0x01, 0x14, 0x68, 0x61, 0x6e, + 0x64, 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x01, + 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x5f, + 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x01, 0x20, 0x62, 0x69, 0x67, 0x69, 0x6e, + 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x01, 0x08, 0x75, 0x74, 0x69, + 0x6c, 0x01, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x01, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, + 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, + 0x76, 0x65, 0x01, 0x08, 0x68, 0x65, 0x6c, 0x70, + 0x01, 0x08, 0x6c, 0x6f, 0x61, 0x64, 0x01, 0x08, + 0x65, 0x78, 0x69, 0x74, 0x01, 0x0e, 0x74, 0x6f, + 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x01, 0x14, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x73, 0x01, 0x12, 0x63, 0x6d, 0x64, 0x5f, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x01, 0x24, 0x63, 0x6d, + 0x64, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, + 0x6e, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x01, 0x26, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, + 0x6e, 0x65, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x5f, 0x63, 0x6d, 0x64, 0x01, 0x14, 0x68, + 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x63, 0x6d, + 0x64, 0x01, 0x1c, 0x65, 0x76, 0x61, 0x6c, 0x5f, + 0x61, 0x6e, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x01, 0x22, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x5f, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x01, 0x20, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x5f, 0x65, 0x76, 0x61, 0x6c, + 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x01, 0x1c, + 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x63, + 0x6d, 0x64, 0x5f, 0x65, 0x6e, 0x64, 0x01, 0x16, + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x69, 0x7a, 0x65, + 0x5f, 0x6a, 0x73, 0x01, 0x16, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, + 0x01, 0x18, 0x73, 0x61, 0x76, 0x65, 0x5f, 0x68, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x01, 0x18, + 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x01, 0x16, 0x6c, 0x6f, + 0x61, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x01, 0x06, 0x74, 0x61, 0x62, 0x01, 0x0c, + 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x6f, 0x01, 0x0c, + 0x69, 0x73, 0x61, 0x74, 0x74, 0x79, 0x01, 0x1a, + 0x74, 0x74, 0x79, 0x47, 0x65, 0x74, 0x57, 0x69, + 0x6e, 0x53, 0x69, 0x7a, 0x65, 0x01, 0x12, 0x74, + 0x74, 0x79, 0x53, 0x65, 0x74, 0x52, 0x61, 0x77, + 0x01, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x01, 0x0c, 0x53, 0x49, 0x47, 0x49, 0x4e, 0x54, + 0x01, 0x1c, 0x73, 0x65, 0x74, 0x52, 0x65, 0x61, + 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, + 0x01, 0x02, 0x6c, 0x01, 0x02, 0x69, 0x01, 0x08, + 0x72, 0x65, 0x61, 0x64, 0x01, 0x0c, 0x62, 0x75, + 0x66, 0x66, 0x65, 0x72, 0x01, 0x02, 0x63, 0x01, + 0x02, 0x41, 0x01, 0x02, 0x5a, 0x01, 0x02, 0x61, + 0x01, 0x02, 0x7a, 0x01, 0x02, 0x5f, 0x01, 0x02, + 0x24, 0x01, 0x0a, 0x09, 0x0d, 0x0a, 0x0c, 0x0b, + 0x01, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x73, 0x01, 0x06, 0x73, 0x74, 0x72, 0x01, + 0x06, 0x6c, 0x65, 0x6e, 0x01, 0x0e, 0x73, 0x74, + 0x72, 0x5f, 0x6c, 0x65, 0x6e, 0x01, 0x14, 0x63, + 0x68, 0x61, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x41, + 0x74, 0x01, 0x02, 0x64, 0x01, 0x16, 0x63, 0x6f, + 0x64, 0x65, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x41, + 0x74, 0x01, 0x02, 0x62, 0x01, 0x04, 0x28, 0x29, + 0x01, 0x04, 0x5b, 0x5d, 0x01, 0x04, 0x7b, 0x7d, + 0x01, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x01, + 0x16, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x73, 0x01, 0x02, 0x6a, 0x01, + 0x0a, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x01, 0x08, + 0x70, 0x75, 0x74, 0x73, 0x01, 0x08, 0x6e, 0x6f, + 0x6e, 0x65, 0x01, 0x12, 0x73, 0x75, 0x62, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x01, 0x02, 0x6e, + 0x01, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x01, 0x04, + 0x1b, 0x5b, 0x01, 0x0a, 0x64, 0x65, 0x6c, 0x74, + 0x61, 0x01, 0x02, 0x0a, 0x01, 0x06, 0x6d, 0x69, + 0x6e, 0x01, 0x02, 0x43, 0x01, 0x02, 0x44, 0x01, + 0x0e, 0x63, 0x6d, 0x64, 0x5f, 0x6c, 0x65, 0x6e, + 0x01, 0x14, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x01, 0x04, 0x20, 0x08, + 0x01, 0x06, 0x1b, 0x5b, 0x4a, 0x01, 0x06, 0x6f, + 0x75, 0x74, 0x01, 0x0a, 0x66, 0x6c, 0x75, 0x73, + 0x68, 0x01, 0x0c, 0x63, 0x68, 0x61, 0x72, 0x41, + 0x74, 0x01, 0x06, 0x70, 0x6f, 0x73, 0x01, 0x0a, + 0x63, 0x6c, 0x65, 0x61, 0x72, 0x01, 0x12, 0x74, + 0x72, 0x69, 0x6d, 0x52, 0x69, 0x67, 0x68, 0x74, + 0x01, 0x08, 0x70, 0x75, 0x73, 0x68, 0x01, 0x06, + 0x64, 0x69, 0x72, 0x01, 0x06, 0x65, 0x6e, 0x64, + 0x01, 0x04, 0x70, 0x31, 0x01, 0x04, 0x70, 0x32, + 0x01, 0x04, 0x70, 0x34, 0x01, 0x04, 0x70, 0x33, + 0x01, 0x16, 0x74, 0x6f, 0x55, 0x70, 0x70, 0x65, + 0x72, 0x43, 0x61, 0x73, 0x65, 0x01, 0x16, 0x74, + 0x6f, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x43, 0x61, + 0x73, 0x65, 0x01, 0x02, 0x73, 0x01, 0x3c, 0x0a, + 0x28, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20, 0x43, + 0x74, 0x72, 0x6c, 0x2d, 0x43, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x71, + 0x75, 0x69, 0x74, 0x29, 0x0a, 0x01, 0x08, 0x6c, + 0x69, 0x6e, 0x65, 0x01, 0x02, 0x2e, 0x01, 0x0a, + 0x73, 0x6c, 0x69, 0x63, 0x65, 0x01, 0x08, 0x62, + 0x61, 0x73, 0x65, 0x01, 0x10, 0x62, 0x61, 0x73, + 0x65, 0x5f, 0x70, 0x6f, 0x73, 0x01, 0x06, 0x6f, + 0x62, 0x6a, 0x01, 0x02, 0x5c, 0x01, 0x12, 0x27, + 0x22, 0x60, 0x40, 0x23, 0x29, 0x5d, 0x7d, 0x5c, + 0x01, 0x0e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, + 0x66, 0x01, 0x02, 0x27, 0x01, 0x02, 0x22, 0x01, + 0x02, 0x60, 0x01, 0x02, 0x5d, 0x01, 0x02, 0x2f, + 0x01, 0x0a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x01, + 0x0e, 0x63, 0x74, 0x78, 0x5f, 0x6f, 0x62, 0x6a, + 0x01, 0x02, 0x72, 0x01, 0x0a, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x01, 0x04, 0x6b, 0x77, 0x01, 0x0a, + 0x70, 0x72, 0x6f, 0x70, 0x73, 0x01, 0x08, 0x70, + 0x72, 0x6f, 0x70, 0x01, 0x0c, 0x73, 0x79, 0x6d, + 0x63, 0x6d, 0x70, 0x01, 0x14, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x73, 0x57, 0x69, 0x74, 0x68, 0x01, + 0x26, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x50, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x4e, + 0x61, 0x6d, 0x65, 0x73, 0x01, 0x08, 0x73, 0x6f, + 0x72, 0x74, 0x01, 0x06, 0x63, 0x74, 0x78, 0x01, + 0x06, 0x72, 0x65, 0x73, 0x01, 0x02, 0x74, 0x01, + 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x01, 0x06, 0x63, 0x6f, 0x6c, 0x01, + 0x0c, 0x6e, 0x5f, 0x63, 0x6f, 0x6c, 0x73, 0x01, + 0x06, 0x72, 0x6f, 0x77, 0x01, 0x0c, 0x6e, 0x5f, + 0x72, 0x6f, 0x77, 0x73, 0x01, 0x02, 0x6d, 0x01, + 0x02, 0x28, 0x01, 0x02, 0x29, 0x01, 0x06, 0x6d, + 0x61, 0x78, 0x01, 0x0a, 0x66, 0x6c, 0x6f, 0x6f, + 0x72, 0x01, 0x08, 0x63, 0x65, 0x69, 0x6c, 0x01, + 0x0c, 0x70, 0x61, 0x64, 0x45, 0x6e, 0x64, 0x01, + 0x0a, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x01, 0x0c, + 0x64, 0x65, 0x66, 0x73, 0x74, 0x72, 0x01, 0x04, + 0x63, 0x62, 0x01, 0x02, 0x20, 0x01, 0x0e, 0x74, + 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x01, 0x04, + 0x63, 0x31, 0x01, 0x1a, 0x66, 0x72, 0x6f, 0x6d, + 0x43, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x01, 0x02, 0x1b, 0x01, 0x02, 0x5b, 0x01, + 0x02, 0x4f, 0x01, 0x02, 0x3b, 0x01, 0x06, 0x66, + 0x75, 0x6e, 0x01, 0x0a, 0x72, 0x61, 0x64, 0x69, + 0x78, 0x01, 0x04, 0x2d, 0x30, 0x01, 0x02, 0x2d, + 0x01, 0x04, 0x30, 0x78, 0x01, 0x06, 0x76, 0x61, + 0x6c, 0x01, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x01, 0x14, 0x75, 0x73, + 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, + 0x01, 0x0e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x01, 0x16, 0x62, 0x72, 0x65, 0x61, 0x6b, + 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x01, 0x1c, + 0x6d, 0x61, 0x78, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x01, 0x1e, + 0x6d, 0x61, 0x78, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x01, + 0x1e, 0x6d, 0x61, 0x78, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x01, 0x08, 0x72, 0x65, 0x66, 0x73, 0x01, 0x0c, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x01, 0x0c, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x01, 0x14, + 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x01, 0x12, 0x71, 0x75, 0x6f, 0x74, + 0x65, 0x5f, 0x73, 0x74, 0x72, 0x01, 0x14, 0x70, + 0x75, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x01, 0x18, 0x61, 0x70, 0x70, 0x65, 0x6e, + 0x64, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x01, + 0x12, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x74, + 0x61, 0x67, 0x01, 0x12, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x5f, 0x72, 0x65, 0x63, 0x01, 0x14, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x73, 0x74, + 0x72, 0x01, 0x1e, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6e, 0x61, + 0x6d, 0x65, 0x01, 0x1a, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x74, 0x74, + 0x79, 0x01, 0x10, 0x69, 0x73, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x01, 0x16, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x01, 0x1a, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x5f, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x01, + 0x1a, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x01, 0x1a, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x69, + 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x01, 0x06, 0x6f, + 0x70, 0x74, 0x01, 0x06, 0x64, 0x65, 0x66, 0x01, + 0x12, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, + 0x66, 0x79, 0x01, 0x14, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x41, 0x6c, 0x6c, 0x01, 0x04, + 0x5c, 0x22, 0x01, 0x02, 0x6f, 0x01, 0x08, 0x63, + 0x61, 0x6c, 0x6c, 0x01, 0x04, 0x6e, 0x30, 0x01, + 0x02, 0x6b, 0x01, 0x06, 0x6b, 0x65, 0x79, 0x01, + 0x08, 0x74, 0x79, 0x70, 0x65, 0x01, 0x0e, 0x69, + 0x73, 0x61, 0x72, 0x72, 0x61, 0x79, 0x01, 0x0e, + 0x6e, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x01, + 0x0c, 0x6e, 0x6f, 0x6b, 0x65, 0x79, 0x73, 0x01, + 0x0a, 0x62, 0x72, 0x61, 0x63, 0x65, 0x01, 0x06, + 0x73, 0x65, 0x70, 0x01, 0x12, 0x6f, 0x62, 0x6a, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x01, 0x06, + 0x74, 0x61, 0x67, 0x01, 0x08, 0x63, 0x6f, 0x6e, + 0x73, 0x01, 0x08, 0x64, 0x65, 0x73, 0x63, 0x01, + 0x0c, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x01, + 0x06, 0x2e, 0x2e, 0x2e, 0x01, 0x16, 0x5b, 0x43, + 0x69, 0x72, 0x63, 0x75, 0x6c, 0x61, 0x72, 0x20, + 0x2a, 0x01, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x20, + 0x01, 0x16, 0x74, 0x6f, 0x47, 0x4d, 0x54, 0x53, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x01, 0x04, 0x3a, + 0x20, 0x01, 0x0e, 0x69, 0x73, 0x41, 0x72, 0x72, + 0x61, 0x79, 0x01, 0x06, 0x29, 0x20, 0x5b, 0x01, + 0x16, 0x5b, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x3a, 0x20, 0x01, 0x2c, 0x5b, 0x46, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x28, 0x61, 0x6e, 0x6f, 0x6e, 0x79, 0x6d, 0x6f, + 0x75, 0x73, 0x29, 0x5d, 0x01, 0x04, 0x20, 0x5b, + 0x01, 0x06, 0x5d, 0x20, 0x7b, 0x01, 0x26, 0x3a, + 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x5d, + 0x20, 0x7b, 0x01, 0x04, 0x20, 0x7b, 0x01, 0x02, + 0x7b, 0x01, 0x02, 0x7d, 0x01, 0x02, 0x3c, 0x01, + 0x1a, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x3e, 0x01, 0x0e, + 0x3c, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x3e, 0x01, + 0x08, 0x2e, 0x2e, 0x2e, 0x20, 0x01, 0x16, 0x20, + 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x69, 0x74, 0x65, + 0x6d, 0x73, 0x01, 0x02, 0x3a, 0x01, 0x0c, 0x47, + 0x65, 0x74, 0x74, 0x65, 0x72, 0x01, 0x0c, 0x53, + 0x65, 0x74, 0x74, 0x65, 0x72, 0x01, 0x20, 0x20, + 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x70, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x01, + 0x06, 0x70, 0x6f, 0x70, 0x01, 0x0c, 0x3c, 0x72, + 0x65, 0x66, 0x20, 0x2a, 0x01, 0x04, 0x3e, 0x20, + 0x01, 0x0a, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x01, + 0x10, 0x70, 0x72, 0x6f, 0x70, 0x6e, 0x61, 0x6d, + 0x65, 0x01, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, + 0x01, 0x0c, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, + 0x01, 0x14, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x01, 0x02, 0x2c, 0x01, + 0x0a, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x01, 0x08, + 0x64, 0x61, 0x74, 0x65, 0x01, 0x06, 0x4e, 0x61, + 0x4e, 0x01, 0x0e, 0x6b, 0x65, 0x79, 0x77, 0x6f, + 0x72, 0x64, 0x01, 0x02, 0x77, 0x01, 0x0a, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x01, 0x0c, 0x73, 0x65, + 0x70, 0x6c, 0x65, 0x6e, 0x01, 0x08, 0x6c, 0x61, + 0x73, 0x74, 0x01, 0x04, 0x2c, 0x20, 0x01, 0x0c, + 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x01, 0x0c, + 0x69, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x01, 0x16, + 0x61, 0x76, 0x61, 0x69, 0x6c, 0x5f, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x01, 0x0a, 0x66, 0x69, 0x72, + 0x73, 0x74, 0x01, 0x08, 0x63, 0x6f, 0x6c, 0x73, + 0x01, 0x10, 0x63, 0x6f, 0x6c, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x01, 0x10, 0x65, 0x6e, 0x64, 0x73, + 0x57, 0x69, 0x74, 0x68, 0x01, 0x14, 0x73, 0x68, + 0x6f, 0x77, 0x48, 0x69, 0x64, 0x64, 0x65, 0x6e, + 0x01, 0x0a, 0x64, 0x65, 0x70, 0x74, 0x68, 0x01, + 0x0e, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, + 0x01, 0x0e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, + 0x6c, 0x01, 0x02, 0x70, 0x01, 0x02, 0x3f, 0x01, + 0x08, 0x74, 0x72, 0x69, 0x6d, 0x01, 0x26, 0x55, + 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x3a, 0x20, 0x01, 0x06, 0x73, 0x65, 0x6c, 0x01, + 0x32, 0x2e, 0x68, 0x65, 0x6c, 0x70, 0x20, 0x20, + 0x20, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x68, 0x65, 0x6c, + 0x70, 0x0a, 0x01, 0x10, 0x2e, 0x78, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x01, 0x36, 0x68, 0x65, + 0x78, 0x61, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, + 0x6c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x0a, 0x01, 0x10, 0x2e, 0x64, 0x65, 0x63, 0x20, + 0x20, 0x20, 0x20, 0x01, 0x2e, 0x64, 0x65, 0x63, + 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x20, 0x64, 0x69, 0x73, 0x70, + 0x6c, 0x61, 0x79, 0x0a, 0x01, 0x10, 0x2e, 0x74, + 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x01, 0x2c, + 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x20, 0x74, + 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x0a, 0x01, 0x10, + 0x2e, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x20, + 0x01, 0x3c, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, + 0x20, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x20, + 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x65, 0x76, 0x61, + 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, + 0x01, 0x48, 0x2e, 0x64, 0x65, 0x70, 0x74, 0x68, + 0x20, 0x20, 0x20, 0x73, 0x65, 0x74, 0x20, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x64, 0x65, + 0x70, 0x74, 0x68, 0x20, 0x28, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x01, 0x04, + 0x29, 0x0a, 0x01, 0x10, 0x2e, 0x68, 0x69, 0x64, + 0x64, 0x65, 0x6e, 0x20, 0x01, 0x42, 0x74, 0x6f, + 0x67, 0x67, 0x6c, 0x65, 0x20, 0x68, 0x69, 0x64, + 0x64, 0x65, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x20, 0x64, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x0a, 0x01, + 0x10, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, + 0x20, 0x01, 0x2c, 0x74, 0x6f, 0x67, 0x67, 0x6c, + 0x65, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x65, + 0x64, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x0a, 0x01, 0x10, 0x2e, 0x64, 0x61, 0x72, 0x6b, + 0x20, 0x20, 0x20, 0x01, 0x08, 0x64, 0x61, 0x72, + 0x6b, 0x01, 0x30, 0x73, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x20, 0x64, 0x61, 0x72, 0x6b, 0x20, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x6d, 0x65, 0x0a, 0x01, 0x10, 0x2e, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x20, 0x01, 0x0a, 0x6c, + 0x69, 0x67, 0x68, 0x74, 0x01, 0x32, 0x73, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x20, 0x6c, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, + 0x20, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x0a, 0x01, + 0x38, 0x2e, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x20, + 0x20, 0x20, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x6c, 0x0a, 0x01, 0x4c, 0x2e, + 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, + 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, + 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x01, 0x1c, 0x2e, + 0x71, 0x75, 0x69, 0x74, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x78, 0x69, 0x74, 0x0a, 0x01, 0x02, 0x65, + 0x01, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x4f, 0x66, 0x01, 0x06, 0x2e, + 0x6a, 0x73, 0x01, 0x14, 0x6c, 0x6f, 0x61, 0x64, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x01, 0x1c, + 0x31, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x79, + 0x65, 0x73, 0x20, 0x59, 0x65, 0x73, 0x01, 0x0c, + 0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x4a, 0x01, 0x46, + 0x51, 0x75, 0x69, 0x63, 0x6b, 0x4a, 0x53, 0x2d, + 0x6e, 0x67, 0x20, 0x2d, 0x20, 0x54, 0x79, 0x70, + 0x65, 0x20, 0x22, 0x2e, 0x68, 0x65, 0x6c, 0x70, + 0x22, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68, 0x65, + 0x6c, 0x70, 0x0a, 0x01, 0x08, 0x20, 0x20, 0x20, + 0x20, 0x01, 0x08, 0x65, 0x78, 0x70, 0x72, 0x01, + 0x0c, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x01, + 0x2a, 0x22, 0x75, 0x73, 0x65, 0x20, 0x73, 0x74, + 0x72, 0x69, 0x63, 0x74, 0x22, 0x3b, 0x20, 0x76, + 0x6f, 0x69, 0x64, 0x20, 0x30, 0x3b, 0x01, 0x06, + 0x6e, 0x6f, 0x77, 0x01, 0x14, 0x65, 0x76, 0x61, + 0x6c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x01, + 0x22, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, + 0x63, 0x65, 0x5f, 0x62, 0x61, 0x72, 0x72, 0x69, + 0x65, 0x72, 0x01, 0x0a, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x01, 0x0e, 0x54, 0x68, 0x72, 0x6f, 0x77, + 0x3a, 0x20, 0x01, 0x04, 0x67, 0x63, 0x01, 0x0a, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x01, 0x0e, 0x70, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x01, 0x12, + 0x63, 0x61, 0x6e, 0x5f, 0x72, 0x65, 0x67, 0x65, + 0x78, 0x01, 0x14, 0x70, 0x75, 0x73, 0x68, 0x5f, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x01, 0x14, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x01, 0x12, 0x70, 0x6f, 0x70, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x01, 0x26, 0x70, 0x61, + 0x72, 0x73, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, + 0x74, 0x01, 0x24, 0x70, 0x61, 0x72, 0x73, 0x65, + 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x01, 0x18, 0x70, + 0x61, 0x72, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x01, 0x16, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, + 0x01, 0x18, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x01, 0x16, + 0x6a, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x77, 0x6f, + 0x72, 0x64, 0x73, 0x01, 0x16, 0x6a, 0x73, 0x5f, + 0x6e, 0x6f, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, + 0x01, 0x10, 0x6a, 0x73, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x01, 0x20, 0x70, 0x61, 0x72, 0x73, + 0x65, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x01, 0x12, 0x73, 0x65, + 0x74, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x01, + 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, + 0x01, 0x0a, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x01, + 0x04, 0x69, 0x31, 0x01, 0x02, 0x7c, 0x01, 0x14, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x01, 0x04, 0x74, 0x6f, 0x01, 0x6a, + 0x62, 0x72, 0x65, 0x61, 0x6b, 0x7c, 0x63, 0x61, + 0x73, 0x65, 0x7c, 0x63, 0x61, 0x74, 0x63, 0x68, + 0x7c, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, + 0x65, 0x7c, 0x64, 0x65, 0x62, 0x75, 0x67, 0x67, + 0x65, 0x72, 0x7c, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x7c, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x7c, 0x64, 0x6f, 0x7c, 0x01, 0x5e, 0x65, + 0x6c, 0x73, 0x65, 0x7c, 0x66, 0x69, 0x6e, 0x61, + 0x6c, 0x6c, 0x79, 0x7c, 0x66, 0x6f, 0x72, 0x7c, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x7c, 0x69, 0x66, 0x7c, 0x69, 0x6e, 0x7c, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6f, + 0x66, 0x7c, 0x6e, 0x65, 0x77, 0x7c, 0x01, 0x5e, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x7c, 0x73, + 0x77, 0x69, 0x74, 0x63, 0x68, 0x7c, 0x74, 0x68, + 0x69, 0x73, 0x7c, 0x74, 0x68, 0x72, 0x6f, 0x77, + 0x7c, 0x74, 0x72, 0x79, 0x7c, 0x74, 0x79, 0x70, + 0x65, 0x6f, 0x66, 0x7c, 0x77, 0x68, 0x69, 0x6c, + 0x65, 0x7c, 0x77, 0x69, 0x74, 0x68, 0x7c, 0x01, + 0x5a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x7c, 0x63, + 0x6f, 0x6e, 0x73, 0x74, 0x7c, 0x65, 0x6e, 0x75, + 0x6d, 0x7c, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x7c, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x7c, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x73, 0x7c, + 0x73, 0x75, 0x70, 0x65, 0x72, 0x7c, 0x01, 0x66, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x7c, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x7c, 0x6c, 0x65, 0x74, + 0x7c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, + 0x7c, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, + 0x7c, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x7c, 0x01, 0x28, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x7c, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x63, 0x7c, 0x79, 0x69, 0x65, 0x6c, 0x64, + 0x7c, 0x01, 0x4e, 0x75, 0x6e, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x65, 0x64, 0x7c, 0x6e, 0x75, 0x6c, + 0x6c, 0x7c, 0x74, 0x72, 0x75, 0x65, 0x7c, 0x66, + 0x61, 0x6c, 0x73, 0x65, 0x7c, 0x49, 0x6e, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x79, 0x7c, 0x4e, 0x61, + 0x4e, 0x7c, 0x01, 0x1e, 0x65, 0x76, 0x61, 0x6c, + 0x7c, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x7c, 0x01, 0x0c, 0x61, 0x77, 0x61, + 0x69, 0x74, 0x7c, 0x01, 0x7a, 0x7c, 0x74, 0x68, + 0x69, 0x73, 0x7c, 0x73, 0x75, 0x70, 0x65, 0x72, + 0x7c, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, + 0x65, 0x64, 0x7c, 0x6e, 0x75, 0x6c, 0x6c, 0x7c, + 0x74, 0x72, 0x75, 0x65, 0x7c, 0x66, 0x61, 0x6c, + 0x73, 0x65, 0x7c, 0x49, 0x6e, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x79, 0x7c, 0x4e, 0x61, 0x4e, 0x7c, + 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x7c, 0x01, 0x14, 0x7c, 0x76, 0x6f, 0x69, + 0x64, 0x7c, 0x76, 0x61, 0x72, 0x7c, 0x01, 0x02, + 0x09, 0x01, 0x02, 0x0d, 0x01, 0x02, 0x2b, 0x01, + 0x1c, 0x78, 0x64, 0x67, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x5f, 0x68, 0x6f, 0x6d, 0x65, 0x01, + 0x08, 0x68, 0x6f, 0x6d, 0x65, 0x01, 0x0c, 0x67, + 0x65, 0x74, 0x65, 0x6e, 0x76, 0x01, 0x1c, 0x58, + 0x44, 0x47, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, + 0x5f, 0x48, 0x4f, 0x4d, 0x45, 0x01, 0x08, 0x48, + 0x4f, 0x4d, 0x45, 0x01, 0x10, 0x70, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x01, 0x0a, 0x6c, + 0x69, 0x6e, 0x75, 0x78, 0x01, 0x1a, 0x2f, 0x2e, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x01, 0x08, 0x73, 0x74, 0x61, + 0x74, 0x01, 0x16, 0x55, 0x53, 0x45, 0x52, 0x50, + 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x01, 0x04, + 0x2f, 0x2e, 0x01, 0x02, 0x66, 0x01, 0x08, 0x6f, + 0x70, 0x65, 0x6e, 0x01, 0x16, 0x71, 0x6a, 0x73, + 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x01, 0x0a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x01, + 0x10, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, + 0x65, 0x01, 0x12, 0x43, 0x4f, 0x4c, 0x4f, 0x52, + 0x46, 0x47, 0x42, 0x47, 0x01, 0x10, 0x4e, 0x4f, + 0x5f, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x01, 0x0c, + 0x61, 0x77, 0x61, 0x69, 0x74, 0x20, 0x01, 0x0e, + 0x63, 0x61, 0x74, 0x63, 0x68, 0x20, 0x28, 0x01, + 0x0c, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x01, + 0x0c, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x01, + 0x0a, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x01, 0x0e, + 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x01, + 0x08, 0x66, 0x6f, 0x72, 0x20, 0x01, 0x12, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x01, 0x08, 0x69, 0x66, 0x20, 0x28, 0x01, 0x0e, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x01, + 0x16, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x6f, 0x66, 0x20, 0x01, 0x08, 0x6c, 0x65, + 0x74, 0x20, 0x01, 0x08, 0x6e, 0x65, 0x77, 0x20, + 0x01, 0x0c, 0x73, 0x75, 0x70, 0x65, 0x72, 0x20, + 0x01, 0x0a, 0x74, 0x72, 0x79, 0x20, 0x7b, 0x01, + 0x0e, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, + 0x01, 0x08, 0x76, 0x61, 0x72, 0x20, 0x01, 0x0e, + 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x01, + 0x0c, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x01, + 0x08, 0x1b, 0x5b, 0x30, 0x6d, 0x01, 0x0a, 0x1b, + 0x5b, 0x33, 0x30, 0x6d, 0x01, 0x0a, 0x62, 0x6c, + 0x61, 0x63, 0x6b, 0x01, 0x0a, 0x1b, 0x5b, 0x33, + 0x31, 0x6d, 0x01, 0x06, 0x72, 0x65, 0x64, 0x01, + 0x0a, 0x1b, 0x5b, 0x33, 0x32, 0x6d, 0x01, 0x0a, + 0x67, 0x72, 0x65, 0x65, 0x6e, 0x01, 0x0a, 0x1b, + 0x5b, 0x33, 0x33, 0x6d, 0x01, 0x0c, 0x79, 0x65, + 0x6c, 0x6c, 0x6f, 0x77, 0x01, 0x0a, 0x1b, 0x5b, + 0x33, 0x34, 0x6d, 0x01, 0x08, 0x62, 0x6c, 0x75, + 0x65, 0x01, 0x0a, 0x1b, 0x5b, 0x33, 0x35, 0x6d, + 0x01, 0x0e, 0x6d, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x61, 0x01, 0x0a, 0x1b, 0x5b, 0x33, 0x36, 0x6d, + 0x01, 0x08, 0x63, 0x79, 0x61, 0x6e, 0x01, 0x0a, + 0x1b, 0x5b, 0x33, 0x37, 0x6d, 0x01, 0x0a, 0x77, + 0x68, 0x69, 0x74, 0x65, 0x01, 0x0e, 0x1b, 0x5b, + 0x33, 0x30, 0x3b, 0x31, 0x6d, 0x01, 0x08, 0x67, + 0x72, 0x61, 0x79, 0x01, 0x08, 0x67, 0x72, 0x65, + 0x79, 0x01, 0x0e, 0x1b, 0x5b, 0x33, 0x31, 0x3b, + 0x31, 0x6d, 0x01, 0x14, 0x62, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x5f, 0x72, 0x65, 0x64, 0x01, 0x0e, + 0x1b, 0x5b, 0x33, 0x32, 0x3b, 0x31, 0x6d, 0x01, + 0x18, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, + 0x67, 0x72, 0x65, 0x65, 0x6e, 0x01, 0x0e, 0x1b, + 0x5b, 0x33, 0x33, 0x3b, 0x31, 0x6d, 0x01, 0x1a, + 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x79, + 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x01, 0x0e, 0x1b, + 0x5b, 0x33, 0x34, 0x3b, 0x31, 0x6d, 0x01, 0x16, + 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x62, + 0x6c, 0x75, 0x65, 0x01, 0x0e, 0x1b, 0x5b, 0x33, + 0x35, 0x3b, 0x31, 0x6d, 0x01, 0x1c, 0x62, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6d, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x61, 0x01, 0x0e, 0x1b, 0x5b, + 0x33, 0x36, 0x3b, 0x31, 0x6d, 0x01, 0x16, 0x62, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x63, 0x79, + 0x61, 0x6e, 0x01, 0x0e, 0x1b, 0x5b, 0x33, 0x37, + 0x3b, 0x31, 0x6d, 0x01, 0x18, 0x62, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x5f, 0x77, 0x68, 0x69, 0x74, + 0x65, 0x01, 0x0c, 0x71, 0x6a, 0x73, 0x20, 0x3e, + 0x20, 0x01, 0x0c, 0x20, 0x20, 0x2e, 0x2e, 0x2e, + 0x20, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, + 0x02, 0x03, 0x01, 0x02, 0x04, 0x01, 0x02, 0x05, + 0x01, 0x02, 0x06, 0x01, 0x02, 0x07, 0x01, 0x02, + 0x08, 0x01, 0x02, 0x0b, 0x01, 0x02, 0x0c, 0x01, + 0x02, 0x0e, 0x01, 0x02, 0x10, 0x01, 0x02, 0x11, + 0x01, 0x02, 0x12, 0x01, 0x02, 0x13, 0x01, 0x02, + 0x14, 0x01, 0x02, 0x17, 0x01, 0x02, 0x18, 0x01, + 0x02, 0x19, 0x01, 0x06, 0x1b, 0x4f, 0x41, 0x01, + 0x06, 0x1b, 0x4f, 0x42, 0x01, 0x06, 0x1b, 0x4f, + 0x43, 0x01, 0x06, 0x1b, 0x4f, 0x44, 0x01, 0x06, + 0x1b, 0x4f, 0x46, 0x01, 0x06, 0x1b, 0x4f, 0x48, + 0x01, 0x0c, 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x43, + 0x01, 0x0c, 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x44, + 0x01, 0x08, 0x1b, 0x5b, 0x31, 0x7e, 0x01, 0x08, + 0x1b, 0x5b, 0x33, 0x7e, 0x01, 0x08, 0x1b, 0x5b, + 0x34, 0x7e, 0x01, 0x08, 0x1b, 0x5b, 0x35, 0x7e, + 0x01, 0x08, 0x1b, 0x5b, 0x36, 0x7e, 0x01, 0x06, + 0x1b, 0x5b, 0x41, 0x01, 0x06, 0x1b, 0x5b, 0x42, + 0x01, 0x06, 0x1b, 0x5b, 0x43, 0x01, 0x06, 0x1b, + 0x5b, 0x44, 0x01, 0x06, 0x1b, 0x5b, 0x46, 0x01, + 0x06, 0x1b, 0x5b, 0x48, 0x01, 0x04, 0x1b, 0x7f, + 0x01, 0x04, 0x1b, 0x62, 0x01, 0x04, 0x1b, 0x64, + 0x01, 0x04, 0x1b, 0x66, 0x01, 0x04, 0x1b, 0x6b, + 0x01, 0x04, 0x1b, 0x6c, 0x01, 0x04, 0x1b, 0x74, + 0x01, 0x04, 0x1b, 0x75, 0x01, 0x02, 0x7f, 0x01, + 0x02, 0x78, 0x01, 0x06, 0x64, 0x65, 0x63, 0x01, + 0x08, 0x74, 0x69, 0x6d, 0x65, 0x01, 0x0c, 0x73, + 0x74, 0x72, 0x69, 0x63, 0x74, 0x01, 0x0c, 0x68, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x01, 0x08, 0x71, + 0x75, 0x69, 0x74, 0x0d, 0xc6, 0x03, 0x03, 0xc8, + 0x03, 0xca, 0x03, 0xcc, 0x03, 0x00, 0x00, 0x03, + 0x00, 0xfe, 0x01, 0x00, 0x01, 0xfe, 0x01, 0x01, + 0x02, 0xfe, 0x01, 0x02, 0x00, 0x0c, 0x20, 0x02, + 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, + 0x01, 0x0f, 0x00, 0xce, 0x03, 0x00, 0x0d, 0xd0, + 0x03, 0x01, 0x0d, 0xd2, 0x03, 0x02, 0x0d, 0x0c, + 0x43, 0x02, 0x01, 0x00, 0x01, 0x8d, 0x01, 0x01, + 0x15, 0x03, 0x5e, 0xf9, 0x0d, 0x8e, 0x01, 0xd4, + 0x03, 0x00, 0x01, 0x40, 0xa8, 0x02, 0x00, 0x00, + 0x40, 0xb0, 0x02, 0x00, 0x01, 0x40, 0xae, 0x02, + 0x00, 0x02, 0x40, 0xb2, 0x02, 0x00, 0x03, 0x40, + 0xe4, 0x02, 0x00, 0x04, 0x40, 0xce, 0x02, 0x00, + 0x05, 0x40, 0xaa, 0x02, 0x00, 0x06, 0x40, 0xbc, + 0x02, 0x00, 0x07, 0x40, 0xc4, 0x02, 0x00, 0x08, + 0x40, 0xac, 0x02, 0x00, 0x09, 0x40, 0xb4, 0x02, + 0x00, 0x0a, 0x00, 0xb8, 0x02, 0x00, 0x0b, 0x40, + 0xba, 0x02, 0x00, 0x0c, 0x40, 0xd6, 0x03, 0x00, + 0x0d, 0x40, 0xd8, 0x03, 0x00, 0x0e, 0x40, 0xda, + 0x03, 0x00, 0x0f, 0x40, 0xdc, 0x03, 0x00, 0x10, + 0x00, 0xde, 0x03, 0x00, 0x11, 0x40, 0xe0, 0x03, + 0x00, 0x12, 0x40, 0xe2, 0x03, 0x00, 0x13, 0x40, + 0xe4, 0x03, 0x00, 0x14, 0x40, 0xe6, 0x03, 0x00, + 0x15, 0x40, 0xe8, 0x03, 0x00, 0x16, 0x40, 0xea, + 0x03, 0x00, 0x17, 0x40, 0xec, 0x03, 0x00, 0x18, + 0x40, 0xee, 0x03, 0x00, 0x19, 0x40, 0xf0, 0x03, + 0x00, 0x1a, 0x40, 0xf2, 0x03, 0x00, 0x1b, 0x40, + 0xf4, 0x03, 0x00, 0x1c, 0x40, 0xf6, 0x03, 0x00, + 0x1d, 0x40, 0xf8, 0x03, 0x00, 0x1e, 0x40, 0xfa, + 0x03, 0x00, 0x1f, 0x40, 0xfc, 0x03, 0x00, 0x20, + 0x40, 0xfe, 0x03, 0x00, 0x21, 0x40, 0x80, 0x04, + 0x00, 0x22, 0x40, 0x82, 0x04, 0x00, 0x23, 0x40, + 0x84, 0x04, 0x00, 0x24, 0x40, 0x86, 0x04, 0x00, + 0x25, 0x40, 0x88, 0x04, 0x00, 0x26, 0x40, 0x8a, + 0x04, 0x00, 0x27, 0x40, 0x8c, 0x04, 0x00, 0x28, + 0x40, 0x8e, 0x04, 0x00, 0x29, 0x40, 0x90, 0x04, + 0x00, 0x2a, 0x40, 0x92, 0x04, 0x00, 0x2b, 0x40, + 0x94, 0x04, 0x00, 0x2c, 0x40, 0x96, 0x04, 0x00, + 0x2d, 0x40, 0x98, 0x04, 0x00, 0x2e, 0x40, 0x9a, + 0x04, 0x00, 0x2f, 0x40, 0x9c, 0x04, 0x00, 0x30, + 0x40, 0x9e, 0x04, 0x00, 0x31, 0x40, 0xa0, 0x04, + 0x00, 0x32, 0x40, 0xa2, 0x04, 0x00, 0x33, 0x40, + 0xa4, 0x04, 0x00, 0x34, 0x40, 0xa6, 0x04, 0x00, + 0x35, 0x00, 0xa8, 0x04, 0x00, 0x36, 0x40, 0xaa, + 0x04, 0x00, 0x37, 0x40, 0xac, 0x04, 0x00, 0x38, + 0x40, 0xae, 0x04, 0x00, 0x39, 0x40, 0xb0, 0x04, + 0x00, 0x3a, 0x40, 0xb2, 0x04, 0x00, 0x3b, 0x40, + 0xb4, 0x04, 0x00, 0x3c, 0x40, 0xb6, 0x04, 0x00, + 0x3d, 0x40, 0xb8, 0x04, 0x00, 0x3e, 0x40, 0xba, + 0x04, 0x00, 0x3f, 0x40, 0xbc, 0x04, 0x00, 0x40, + 0x40, 0xbe, 0x04, 0x00, 0x41, 0x40, 0xc0, 0x04, + 0x00, 0x42, 0x40, 0xc2, 0x04, 0x00, 0x43, 0x40, + 0xc4, 0x04, 0x00, 0x44, 0x40, 0xc6, 0x04, 0x00, + 0x45, 0x00, 0xc8, 0x04, 0x00, 0x46, 0x00, 0xca, + 0x04, 0x00, 0x47, 0x40, 0xcc, 0x04, 0x00, 0x48, + 0x00, 0xce, 0x04, 0x00, 0x49, 0x00, 0xd0, 0x04, + 0x00, 0x4a, 0x00, 0xd2, 0x04, 0x00, 0x4b, 0x00, + 0xd4, 0x04, 0x00, 0x4c, 0x40, 0xd6, 0x04, 0x00, + 0x4d, 0x40, 0xd8, 0x04, 0x00, 0x4e, 0x00, 0xda, + 0x04, 0x00, 0x4f, 0x00, 0xdc, 0x04, 0x00, 0x50, + 0x00, 0xde, 0x04, 0x00, 0x51, 0x00, 0xe0, 0x04, + 0x00, 0x52, 0x40, 0xe2, 0x04, 0x00, 0x53, 0x00, + 0xe4, 0x04, 0x00, 0x54, 0x00, 0xe6, 0x04, 0x00, + 0x55, 0x40, 0xe8, 0x04, 0x00, 0x56, 0x00, 0xea, + 0x04, 0x00, 0x57, 0x00, 0xec, 0x04, 0x00, 0x58, + 0x40, 0xee, 0x04, 0x00, 0x59, 0x00, 0xf0, 0x04, + 0x00, 0x5a, 0x00, 0xf2, 0x04, 0x00, 0x5b, 0x00, + 0xf4, 0x04, 0x00, 0x5c, 0x00, 0xf6, 0x04, 0x00, + 0x5d, 0x00, 0xf8, 0x04, 0x00, 0x5e, 0x00, 0xfa, + 0x04, 0x00, 0x5f, 0x00, 0xfc, 0x04, 0x00, 0x60, + 0x40, 0xfe, 0x04, 0x00, 0x61, 0x00, 0x80, 0x05, + 0x00, 0x62, 0x00, 0x82, 0x05, 0x00, 0x63, 0x00, + 0x84, 0x05, 0x00, 0x64, 0x00, 0x86, 0x05, 0x00, + 0x65, 0x00, 0x88, 0x05, 0x00, 0x66, 0x40, 0x8a, + 0x05, 0x00, 0x67, 0x00, 0x8c, 0x05, 0x00, 0x68, + 0x40, 0x8e, 0x05, 0x00, 0x69, 0x40, 0x90, 0x05, + 0x00, 0x6a, 0x40, 0x92, 0x05, 0x00, 0x6b, 0x40, + 0x94, 0x05, 0x00, 0x6c, 0x40, 0x96, 0x05, 0x00, + 0x6d, 0x40, 0x98, 0x05, 0x00, 0x6e, 0x40, 0x9a, + 0x05, 0x00, 0x6f, 0x40, 0x9c, 0x05, 0x00, 0x70, + 0x40, 0x9e, 0x05, 0x00, 0x71, 0x40, 0xa0, 0x05, + 0x00, 0x72, 0x40, 0xa2, 0x05, 0x00, 0x73, 0x40, + 0xa4, 0x05, 0x00, 0x74, 0x40, 0xa6, 0x05, 0x00, + 0x75, 0x40, 0xa8, 0x05, 0x00, 0x76, 0x40, 0xaa, + 0x05, 0x00, 0x77, 0x40, 0xac, 0x05, 0x00, 0x78, + 0x40, 0xae, 0x05, 0x00, 0x79, 0x40, 0xb0, 0x05, + 0x00, 0x7a, 0x40, 0xb2, 0x05, 0x00, 0x7b, 0x40, + 0xb4, 0x05, 0x00, 0x7c, 0x00, 0xb6, 0x05, 0x00, + 0x7d, 0x40, 0xb8, 0x05, 0x00, 0x7e, 0x40, 0xba, + 0x05, 0x00, 0x7f, 0x40, 0xbc, 0x05, 0x00, 0x80, + 0x01, 0x00, 0xbe, 0x05, 0x00, 0x81, 0x01, 0x40, + 0xc0, 0x05, 0x00, 0x82, 0x01, 0x40, 0xc2, 0x05, + 0x00, 0x83, 0x01, 0x40, 0xc4, 0x05, 0x00, 0x84, + 0x01, 0x40, 0xc6, 0x05, 0x00, 0x85, 0x01, 0x40, + 0xc8, 0x05, 0x00, 0x86, 0x01, 0x40, 0xca, 0x05, + 0x00, 0x87, 0x01, 0x40, 0xcc, 0x05, 0x00, 0x88, + 0x01, 0x40, 0xce, 0x05, 0x00, 0x89, 0x01, 0x40, + 0xd0, 0x05, 0x00, 0x8a, 0x01, 0x40, 0xd2, 0x05, + 0x00, 0x8b, 0x01, 0x00, 0xd4, 0x05, 0x00, 0x8c, + 0x01, 0x00, 0xce, 0x03, 0x00, 0x0c, 0xd0, 0x03, + 0x01, 0x0c, 0xd2, 0x03, 0x02, 0x0c, 0x0c, 0x43, + 0x02, 0x01, 0xa6, 0x04, 0x00, 0x01, 0x00, 0x04, + 0x08, 0x00, 0x89, 0x01, 0x01, 0xd6, 0x05, 0x00, + 0x00, 0x00, 0x9e, 0x04, 0x31, 0x01, 0xce, 0x03, + 0x00, 0x0c, 0xa2, 0x04, 0x33, 0x01, 0xd0, 0x03, + 0x01, 0x0c, 0xa8, 0x04, 0x36, 0x01, 0xa0, 0x04, + 0x32, 0x01, 0xce, 0x02, 0x05, 0x01, 0xaa, 0x04, + 0x37, 0x01, 0x66, 0x01, 0x00, 0x42, 0x0d, 0x00, + 0x00, 0x00, 0x43, 0x6c, 0x01, 0x00, 0x00, 0x24, + 0x00, 0x00, 0xe3, 0xbe, 0x50, 0xe5, 0x66, 0x03, + 0x00, 0x43, 0x6d, 0x01, 0x00, 0x00, 0xdf, 0x24, + 0x01, 0x00, 0xec, 0x35, 0x66, 0x03, 0x00, 0x42, + 0x6e, 0x01, 0x00, 0x00, 0xec, 0x14, 0x66, 0x03, + 0x00, 0x43, 0x6e, 0x01, 0x00, 0x00, 0xdf, 0x24, + 0x01, 0x00, 0xcf, 0xec, 0x05, 0xc7, 0xb6, 0x48, + 0xe5, 0x66, 0x03, 0x00, 0x42, 0x6f, 0x01, 0x00, + 0x00, 0xec, 0x0e, 0x66, 0x03, 0x00, 0x43, 0x6f, + 0x01, 0x00, 0x00, 0xdf, 0x24, 0x01, 0x00, 0x0e, + 0x66, 0x03, 0x00, 0x43, 0x70, 0x01, 0x00, 0x00, + 0x66, 0x03, 0x00, 0x42, 0x71, 0x01, 0x00, 0x00, + 0x5f, 0x04, 0x00, 0x24, 0x02, 0x00, 0x0e, 0x5f, + 0x06, 0x00, 0x11, 0xbe, 0x40, 0x21, 0x01, 0x00, + 0x60, 0x05, 0x00, 0x66, 0x03, 0x00, 0x43, 0x72, + 0x01, 0x00, 0x00, 0xdf, 0x5f, 0x07, 0x00, 0x24, + 0x02, 0x00, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xa8, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, + 0x00, 0xac, 0x04, 0x38, 0x01, 0xdf, 0xb9, 0xf1, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xaa, 0x04, 0x00, + 0x02, 0x00, 0x06, 0x04, 0x00, 0x28, 0x02, 0xe6, + 0x05, 0x00, 0x00, 0x00, 0xe8, 0x05, 0x00, 0x01, + 0x00, 0xd0, 0x03, 0x01, 0x0c, 0x9e, 0x04, 0x31, + 0x01, 0xa0, 0x04, 0x32, 0x01, 0xac, 0x04, 0x38, + 0x01, 0x66, 0x00, 0x00, 0x43, 0x75, 0x01, 0x00, + 0x00, 0xe0, 0xe1, 0x42, 0x76, 0x01, 0x00, 0x00, + 0xb6, 0xe1, 0xeb, 0x24, 0x04, 0x00, 0xcb, 0xb6, + 0xcc, 0xc8, 0xc7, 0xa7, 0xec, 0x0b, 0xe2, 0xe1, + 0xc8, 0x48, 0xf1, 0x0e, 0x94, 0x01, 0xee, 0xf2, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xac, 0x04, 0x01, + 0x00, 0x01, 0x04, 0x04, 0x00, 0x5f, 0x01, 0xee, + 0x05, 0x00, 0x01, 0x00, 0xe6, 0x03, 0x15, 0x01, + 0xa4, 0x05, 0x74, 0x01, 0x9a, 0x04, 0x2f, 0x01, + 0x9c, 0x04, 0x30, 0x01, 0xdf, 0x97, 0xec, 0x06, + 0xe0, 0xd3, 0xf1, 0x0e, 0x29, 0xe1, 0xb6, 0xb0, + 0xec, 0x24, 0xd3, 0xbf, 0x80, 0x00, 0xaa, 0xec, + 0x1d, 0xd3, 0xbf, 0xc0, 0x00, 0xa7, 0xec, 0x16, + 0xe2, 0xbc, 0xa0, 0xd3, 0xbe, 0x3f, 0xa3, 0xa5, + 0xe6, 0xe1, 0x8f, 0xe9, 0xb6, 0xaf, 0xec, 0x33, + 0xe0, 0xe2, 0xf1, 0x0e, 0x29, 0xd3, 0xbf, 0xc0, + 0x00, 0xaa, 0xec, 0x21, 0xd3, 0xbf, 0xf8, 0x00, + 0xa7, 0xec, 0x1a, 0xb7, 0xd3, 0xbf, 0xe0, 0x00, + 0xaa, 0x9e, 0xd3, 0xbf, 0xf0, 0x00, 0xaa, 0x9e, + 0xe5, 0xd3, 0xb7, 0xbc, 0xe1, 0x9f, 0xa0, 0xb7, + 0x9f, 0xa3, 0xe6, 0x29, 0xb6, 0xe5, 0xe0, 0xd3, + 0xf1, 0x0e, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xae, + 0x04, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x35, + 0x01, 0xee, 0x05, 0x00, 0x01, 0x00, 0xd3, 0x98, + 0x04, 0x49, 0x00, 0x00, 0x00, 0xaf, 0x11, 0xec, + 0x2a, 0x0e, 0xd3, 0x04, 0x78, 0x01, 0x00, 0x00, + 0xaa, 0x11, 0xec, 0x09, 0x0e, 0xd3, 0x04, 0x79, + 0x01, 0x00, 0x00, 0xa8, 0x11, 0xed, 0x14, 0x0e, + 0xd3, 0x04, 0x7a, 0x01, 0x00, 0x00, 0xaa, 0x11, + 0xec, 0x09, 0x0e, 0xd3, 0x04, 0x7b, 0x01, 0x00, + 0x00, 0xa8, 0x28, 0x0c, 0x43, 0x02, 0x01, 0xb0, + 0x04, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x19, + 0x01, 0xee, 0x05, 0x00, 0x01, 0x00, 0x07, 0x02, + 0x30, 0x07, 0x02, 0x39, 0xd3, 0x98, 0x04, 0x49, + 0x00, 0x00, 0x00, 0xaf, 0x11, 0xec, 0x0e, 0x0e, + 0xd3, 0xc0, 0x00, 0xaa, 0x11, 0xec, 0x06, 0x0e, + 0xd3, 0xc0, 0x01, 0xa8, 0x28, 0x0c, 0x43, 0x02, + 0x01, 0xb2, 0x04, 0x01, 0x00, 0x01, 0x02, 0x02, + 0x00, 0x2d, 0x01, 0xee, 0x05, 0x00, 0x01, 0x00, + 0xae, 0x04, 0x39, 0x01, 0xb0, 0x04, 0x3a, 0x01, + 0xd3, 0x98, 0x04, 0x49, 0x00, 0x00, 0x00, 0xaf, + 0x11, 0xec, 0x22, 0x0e, 0xdf, 0xd3, 0xf1, 0x11, + 0xed, 0x1b, 0x0e, 0xe0, 0xd3, 0xf1, 0x11, 0xed, + 0x14, 0x0e, 0xd3, 0x04, 0x7c, 0x01, 0x00, 0x00, + 0xad, 0x11, 0xed, 0x09, 0x0e, 0xd3, 0x04, 0x7d, + 0x01, 0x00, 0x00, 0xad, 0x28, 0x0c, 0x43, 0x02, + 0x01, 0xb4, 0x04, 0x01, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x1d, 0x01, 0xee, 0x05, 0x00, 0x01, 0x00, + 0xd3, 0x98, 0x04, 0x49, 0x00, 0x00, 0x00, 0xaf, + 0x11, 0xec, 0x12, 0x0e, 0x04, 0x7e, 0x01, 0x00, + 0x00, 0x43, 0x7f, 0x01, 0x00, 0x00, 0xd3, 0xb6, + 0x48, 0x24, 0x01, 0x00, 0x28, 0x0c, 0x43, 0x02, + 0x01, 0xb6, 0x04, 0x01, 0x04, 0x01, 0x03, 0x00, + 0x00, 0x32, 0x05, 0x80, 0x06, 0x00, 0x01, 0x00, + 0x82, 0x06, 0x00, 0x00, 0x00, 0xee, 0x05, 0x00, + 0x01, 0x00, 0xe8, 0x05, 0x00, 0x02, 0x00, 0x84, + 0x06, 0x00, 0x03, 0x00, 0xd3, 0xeb, 0xce, 0xb6, + 0xcb, 0xb6, 0xcd, 0xc9, 0xca, 0xa7, 0xec, 0x25, + 0xd3, 0x43, 0x83, 0x01, 0x00, 0x00, 0xc9, 0x24, + 0x01, 0x00, 0xd0, 0x01, 0x00, 0xdc, 0x00, 0x00, + 0xa7, 0x11, 0xed, 0x09, 0x0e, 0xc8, 0x01, 0x00, + 0xe0, 0x00, 0x00, 0xaa, 0xec, 0x03, 0x94, 0x00, + 0x94, 0x02, 0xee, 0xd8, 0xc7, 0x28, 0x0c, 0x43, + 0x02, 0x01, 0xb8, 0x04, 0x01, 0x01, 0x01, 0x03, + 0x00, 0x00, 0x29, 0x02, 0xee, 0x05, 0x00, 0x01, + 0x00, 0x88, 0x06, 0x00, 0x00, 0x00, 0xd3, 0x98, + 0x04, 0x49, 0x00, 0x00, 0x00, 0xb0, 0xec, 0x03, + 0x09, 0x28, 0xd3, 0x43, 0x85, 0x01, 0x00, 0x00, + 0xb6, 0x24, 0x01, 0x00, 0xcf, 0x01, 0x00, 0xdc, + 0x00, 0x00, 0xaa, 0x11, 0xec, 0x09, 0x0e, 0xc7, + 0x01, 0x00, 0xe0, 0x00, 0x00, 0xa7, 0x28, 0x0c, + 0x43, 0x02, 0x01, 0xba, 0x04, 0x02, 0x00, 0x02, + 0x03, 0x00, 0x00, 0x23, 0x02, 0xf4, 0x05, 0x00, + 0x01, 0x00, 0x8c, 0x06, 0x00, 0x01, 0x00, 0xd3, + 0xd4, 0x9e, 0x11, 0x04, 0x87, 0x01, 0x00, 0x00, + 0xaf, 0xed, 0x13, 0x11, 0x04, 0x88, 0x01, 0x00, + 0x00, 0xaf, 0xed, 0x0a, 0x11, 0x04, 0x89, 0x01, + 0x00, 0x00, 0xaf, 0xec, 0x03, 0x0a, 0x28, 0x0e, + 0x09, 0x28, 0x0c, 0x43, 0x02, 0x01, 0xbc, 0x04, + 0x03, 0x03, 0x03, 0x06, 0x03, 0x00, 0x62, 0x06, + 0x80, 0x06, 0x00, 0x01, 0x00, 0x94, 0x06, 0x00, + 0x01, 0x00, 0x96, 0x06, 0x00, 0x01, 0x00, 0xe8, + 0x05, 0x00, 0x00, 0x00, 0x98, 0x06, 0x00, 0x01, + 0x00, 0x9a, 0x06, 0x00, 0x02, 0x00, 0xce, 0x03, + 0x00, 0x0c, 0xe0, 0x03, 0x12, 0x01, 0xe4, 0x03, + 0x14, 0x01, 0xd4, 0xcc, 0xc8, 0xd3, 0xeb, 0xa7, + 0xec, 0x5a, 0xd5, 0xc8, 0xcf, 0x48, 0xcd, 0xc8, + 0x90, 0xd0, 0xd3, 0xeb, 0xa7, 0xec, 0x08, 0xd5, + 0xc8, 0x48, 0xc9, 0xad, 0xed, 0xf2, 0x66, 0x00, + 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, 0xe0, 0xe1, + 0xc9, 0x48, 0x11, 0xed, 0x07, 0x0e, 0x04, 0x8f, + 0x01, 0x00, 0x00, 0x48, 0x24, 0x01, 0x00, 0x0e, + 0x66, 0x00, 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, + 0xd3, 0x43, 0x90, 0x01, 0x00, 0x00, 0xc6, 0x24, + 0x02, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x66, 0x00, + 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, 0xe0, 0x04, + 0x8f, 0x01, 0x00, 0x00, 0x48, 0x24, 0x01, 0x00, + 0x0e, 0xee, 0xa2, 0x29, 0x0c, 0x43, 0x02, 0x01, + 0xbe, 0x04, 0x02, 0x00, 0x02, 0x05, 0x01, 0x00, + 0x1d, 0x02, 0xa2, 0x06, 0x00, 0x01, 0x00, 0xa4, + 0x06, 0x00, 0x01, 0x00, 0xce, 0x03, 0x00, 0x0c, + 0x66, 0x00, 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, + 0x04, 0x93, 0x01, 0x00, 0x00, 0xd3, 0xb7, 0xae, + 0xec, 0x04, 0xd3, 0xee, 0x02, 0xc2, 0x9e, 0xd4, + 0x9e, 0x24, 0x01, 0x00, 0x29, 0x0c, 0x43, 0x02, + 0x01, 0xc0, 0x04, 0x01, 0x02, 0x01, 0x04, 0x05, + 0x00, 0xa1, 0x01, 0x03, 0xa8, 0x06, 0x00, 0x01, + 0x00, 0xe8, 0x05, 0x00, 0x00, 0x00, 0xe6, 0x05, + 0x00, 0x01, 0x00, 0xa4, 0x04, 0x34, 0x01, 0xa2, + 0x04, 0x33, 0x01, 0xce, 0x03, 0x00, 0x0c, 0xb8, + 0x02, 0x0b, 0x01, 0xbe, 0x04, 0x41, 0x01, 0xd3, + 0xb6, 0xa9, 0xec, 0x4d, 0xd3, 0xb6, 0xae, 0x6a, + 0x97, 0x00, 0x00, 0x00, 0xdf, 0xe0, 0xb7, 0x9f, + 0xad, 0xec, 0x19, 0x66, 0x02, 0x00, 0x43, 0x8e, + 0x01, 0x00, 0x00, 0x04, 0x95, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xb6, 0xe3, 0xd3, 0x8f, + 0xd7, 0xee, 0xda, 0xe2, 0x43, 0x96, 0x01, 0x00, + 0x00, 0xe0, 0xb7, 0x9f, 0xdf, 0x9f, 0xd3, 0x24, + 0x02, 0x00, 0xcc, 0x5f, 0x04, 0x00, 0xc8, 0x04, + 0x97, 0x01, 0x00, 0x00, 0xf2, 0x0e, 0xd3, 0xc8, + 0x9f, 0xd7, 0xdf, 0xc8, 0x9e, 0xe3, 0xee, 0xb5, + 0xd3, 0x8d, 0xd7, 0xd3, 0xb6, 0xae, 0xec, 0x48, + 0xdf, 0xb6, 0xad, 0xec, 0x22, 0x5f, 0x04, 0x00, + 0xb7, 0x04, 0x78, 0x01, 0x00, 0x00, 0xf2, 0x0e, + 0x5f, 0x04, 0x00, 0xe0, 0xb7, 0x9f, 0x04, 0x97, + 0x01, 0x00, 0x00, 0xf2, 0x0e, 0xd3, 0x8f, 0xd7, + 0xe0, 0xb7, 0x9f, 0xe3, 0xee, 0xd6, 0xe2, 0x43, + 0x96, 0x01, 0x00, 0x00, 0xd3, 0xdf, 0x24, 0x02, + 0x00, 0xcc, 0x5f, 0x04, 0x00, 0xc8, 0x04, 0x98, + 0x01, 0x00, 0x00, 0xf2, 0x0e, 0xd3, 0xc8, 0x9f, + 0xd7, 0xdf, 0xc8, 0x9f, 0xe3, 0xee, 0xb5, 0x29, + 0x0c, 0x43, 0x02, 0x01, 0xc2, 0x04, 0x00, 0x05, + 0x00, 0x06, 0x0d, 0x00, 0x9c, 0x02, 0x05, 0xe8, + 0x05, 0x00, 0x00, 0x00, 0xb2, 0x06, 0x00, 0x01, + 0x00, 0x80, 0x06, 0x00, 0x02, 0x00, 0x94, 0x06, + 0x00, 0x03, 0x00, 0xb4, 0x06, 0x00, 0x04, 0x00, + 0x8c, 0x04, 0x28, 0x01, 0x90, 0x04, 0x2a, 0x01, + 0xea, 0x03, 0x17, 0x01, 0x92, 0x04, 0x2b, 0x01, + 0xce, 0x03, 0x00, 0x0c, 0xc0, 0x04, 0x42, 0x01, + 0xb6, 0x04, 0x3d, 0x01, 0x88, 0x04, 0x26, 0x01, + 0xcc, 0x05, 0x88, 0x01, 0x01, 0xbc, 0x04, 0x40, + 0x01, 0xa4, 0x04, 0x34, 0x01, 0xa2, 0x04, 0x33, + 0x01, 0x8e, 0x04, 0x29, 0x01, 0xdf, 0xe0, 0xae, + 0x6a, 0xc6, 0x00, 0x00, 0x00, 0xe1, 0x97, 0xec, + 0x32, 0xe0, 0x43, 0x90, 0x01, 0x00, 0x00, 0xb6, + 0xe2, 0x24, 0x02, 0x00, 0xdf, 0x43, 0x90, 0x01, + 0x00, 0x00, 0xb6, 0xe2, 0x24, 0x02, 0x00, 0xad, + 0xec, 0x19, 0x66, 0x04, 0x00, 0x43, 0x8e, 0x01, + 0x00, 0x00, 0xdf, 0x43, 0x90, 0x01, 0x00, 0x00, + 0xe2, 0x24, 0x01, 0x00, 0x24, 0x01, 0x00, 0x0e, + 0xee, 0x53, 0x5f, 0x05, 0x00, 0x5f, 0x06, 0x00, + 0xe0, 0x43, 0x90, 0x01, 0x00, 0x00, 0xb6, 0xe2, + 0x24, 0x02, 0x00, 0xf1, 0x8d, 0xf1, 0x0e, 0xe1, + 0xec, 0x2e, 0x5f, 0x07, 0x00, 0xec, 0x0e, 0x5f, + 0x07, 0x00, 0x04, 0x95, 0x01, 0x00, 0x00, 0x9e, + 0xdf, 0x9e, 0xee, 0x02, 0xdf, 0xd1, 0xeb, 0xdf, + 0xeb, 0x9f, 0xce, 0x5f, 0x08, 0x00, 0xc9, 0xf1, + 0xc4, 0x04, 0x5f, 0x09, 0x00, 0xc9, 0xca, 0xc3, + 0x04, 0xb8, 0x48, 0xf3, 0x0e, 0xee, 0x0e, 0x66, + 0x04, 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, 0xdf, + 0x24, 0x01, 0x00, 0x0e, 0x5f, 0x0a, 0x00, 0x5f, + 0x06, 0x00, 0xdf, 0xf1, 0x9e, 0x5f, 0x0b, 0x00, + 0x9d, 0x61, 0x0a, 0x00, 0xb6, 0xad, 0xec, 0x12, + 0x66, 0x04, 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, + 0x04, 0x9b, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0x66, 0x04, 0x00, 0x43, 0x8e, 0x01, 0x00, + 0x00, 0x04, 0x9c, 0x01, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0xdf, 0xe4, 0xdf, 0xeb, 0xe6, 0x5f, + 0x0c, 0x00, 0xe2, 0xa9, 0xec, 0x19, 0x5f, 0x05, + 0x00, 0x5f, 0x06, 0x00, 0xdf, 0x43, 0x90, 0x01, + 0x00, 0x00, 0xe2, 0x5f, 0x0c, 0x00, 0x24, 0x02, + 0x00, 0xf1, 0xf1, 0x0e, 0xee, 0x1f, 0x5f, 0x0c, + 0x00, 0xe2, 0xa7, 0xec, 0x18, 0x5f, 0x05, 0x00, + 0x5f, 0x06, 0x00, 0xdf, 0x43, 0x90, 0x01, 0x00, + 0x00, 0x5f, 0x0c, 0x00, 0xe2, 0x24, 0x02, 0x00, + 0xf1, 0x8d, 0xf1, 0x0e, 0x5f, 0x0c, 0x00, 0xe6, + 0x66, 0x04, 0x00, 0x42, 0x9d, 0x01, 0x00, 0x00, + 0x43, 0x9e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xc4, 0x04, 0x01, + 0x00, 0x01, 0x04, 0x02, 0x00, 0x22, 0x01, 0x80, + 0x06, 0x00, 0x01, 0x00, 0x8c, 0x04, 0x28, 0x01, + 0x8e, 0x04, 0x29, 0x01, 0xd3, 0xec, 0x1f, 0xdf, + 0x43, 0x90, 0x01, 0x00, 0x00, 0xb6, 0xe0, 0x24, + 0x02, 0x00, 0xd3, 0x9e, 0xdf, 0x43, 0x90, 0x01, + 0x00, 0x00, 0xe0, 0x24, 0x01, 0x00, 0x9e, 0xe3, + 0xe0, 0xd3, 0xeb, 0x9e, 0xe4, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0xc6, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x03, 0x00, 0x98, 0x04, 0x2e, 0x01, + 0x0a, 0xe3, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xc8, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x07, + 0x00, 0x8c, 0x04, 0x28, 0x01, 0x8e, 0x04, 0x29, + 0x01, 0xc2, 0xe3, 0xb6, 0xe4, 0xbe, 0xfe, 0x28, + 0x0c, 0x43, 0x02, 0x01, 0xca, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x29, 0x0c, + 0x43, 0x02, 0x01, 0xcc, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x03, 0x00, 0x8e, 0x04, 0x29, + 0x01, 0xb6, 0xe3, 0x29, 0x0c, 0x43, 0x02, 0x01, + 0xce, 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x04, 0x00, 0x8e, 0x04, 0x29, 0x01, 0x8c, 0x04, + 0x28, 0x01, 0xe0, 0xeb, 0xe3, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0xd0, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x1d, 0x00, 0x8e, 0x04, 0x29, 0x01, + 0x8c, 0x04, 0x28, 0x01, 0xb8, 0x04, 0x3e, 0x01, + 0xdf, 0xe0, 0xeb, 0xa7, 0xec, 0x17, 0xdf, 0x90, + 0xe3, 0xe1, 0xe0, 0x43, 0x9f, 0x01, 0x00, 0x00, + 0xdf, 0x24, 0x01, 0x00, 0xf1, 0xec, 0x06, 0xdf, + 0x90, 0xe3, 0xee, 0xee, 0x29, 0x0c, 0x43, 0x02, + 0x01, 0xd2, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x1c, 0x00, 0x8e, 0x04, 0x29, 0x01, 0xb8, + 0x04, 0x3e, 0x01, 0x8c, 0x04, 0x28, 0x01, 0xdf, + 0xb6, 0xa9, 0xec, 0x17, 0xdf, 0x8f, 0xe3, 0xe0, + 0xe1, 0x43, 0x9f, 0x01, 0x00, 0x00, 0xdf, 0x24, + 0x01, 0x00, 0xf1, 0xec, 0x06, 0xdf, 0x8f, 0xe3, + 0xee, 0xee, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xd4, + 0x04, 0x01, 0x00, 0x01, 0x04, 0x02, 0x00, 0x35, + 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0x8c, 0x04, + 0x28, 0x01, 0xb2, 0x04, 0x3b, 0x01, 0xd3, 0xdf, + 0xeb, 0xa7, 0xec, 0x15, 0xe0, 0xdf, 0x43, 0x9f, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xf1, + 0x97, 0xec, 0x06, 0xd3, 0x90, 0xd7, 0xee, 0xe7, + 0xd3, 0xdf, 0xeb, 0xa7, 0xec, 0x14, 0xe0, 0xdf, + 0x43, 0x9f, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, + 0x00, 0xf1, 0xec, 0x06, 0xd3, 0x90, 0xd7, 0xee, + 0xe8, 0xd3, 0x28, 0x0c, 0x43, 0x02, 0x01, 0xd6, + 0x04, 0x01, 0x00, 0x01, 0x05, 0x02, 0x00, 0x37, + 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xb2, 0x04, + 0x3b, 0x01, 0x8c, 0x04, 0x28, 0x01, 0xd3, 0xb6, + 0xa9, 0xec, 0x17, 0xdf, 0xe0, 0x43, 0x9f, 0x01, + 0x00, 0x00, 0xd3, 0xb7, 0x9f, 0x24, 0x01, 0x00, + 0xf1, 0x97, 0xec, 0x06, 0xd3, 0x8f, 0xd7, 0xee, + 0xe6, 0xd3, 0xb6, 0xa9, 0xec, 0x16, 0xdf, 0xe0, + 0x43, 0x9f, 0x01, 0x00, 0x00, 0xd3, 0xb7, 0x9f, + 0x24, 0x01, 0x00, 0xf1, 0xec, 0x06, 0xd3, 0x8f, + 0xd7, 0xee, 0xe7, 0xd3, 0x28, 0x0c, 0x43, 0x02, + 0x01, 0xd8, 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x00, 0x05, 0x00, 0x8e, 0x04, 0x29, 0x01, 0xd4, + 0x04, 0x4c, 0x01, 0xe0, 0xdf, 0xf1, 0xe3, 0x29, + 0x0c, 0x43, 0x02, 0x01, 0xda, 0x04, 0x00, 0x00, + 0x00, 0x02, 0x02, 0x00, 0x05, 0x00, 0x8e, 0x04, + 0x29, 0x01, 0xd6, 0x04, 0x4d, 0x01, 0xe0, 0xdf, + 0xf1, 0xe3, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xdc, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x0e, + 0x00, 0xba, 0x05, 0x7f, 0x01, 0xdf, 0x04, 0xa1, + 0x01, 0x00, 0x00, 0x49, 0x24, 0x00, 0x00, 0x0e, + 0xbe, 0xfe, 0x28, 0x0c, 0x43, 0x02, 0x01, 0xde, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x17, + 0x00, 0xce, 0x03, 0x00, 0x0c, 0xe0, 0x04, 0x52, + 0x01, 0x8c, 0x04, 0x28, 0x01, 0x66, 0x00, 0x00, + 0x43, 0x8e, 0x01, 0x00, 0x00, 0x04, 0x95, 0x01, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xe0, 0xe1, + 0xf1, 0x0e, 0xb5, 0x28, 0x0c, 0x43, 0x02, 0x01, + 0xe0, 0x04, 0x01, 0x00, 0x01, 0x03, 0x02, 0x00, + 0x36, 0x01, 0x80, 0x06, 0x00, 0x01, 0x00, 0xf4, + 0x03, 0x1c, 0x01, 0xf6, 0x03, 0x1d, 0x01, 0xd3, + 0x43, 0xa2, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xdb, 0xec, 0x27, 0xdf, 0xeb, 0xec, 0x18, 0xdf, + 0xdf, 0xeb, 0xb7, 0x9f, 0x48, 0x97, 0xec, 0x0f, + 0xdf, 0x43, 0x32, 0x00, 0x00, 0x00, 0x8f, 0x44, + 0x32, 0x00, 0x00, 0x00, 0xee, 0xe6, 0xdf, 0x43, + 0xa3, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0x0e, 0xdf, 0xeb, 0xe4, 0x29, 0x0c, 0x43, 0x02, + 0x01, 0xe2, 0x04, 0x00, 0x00, 0x00, 0x03, 0x04, + 0x00, 0x20, 0x00, 0xf6, 0x03, 0x1d, 0x01, 0xf4, + 0x03, 0x1c, 0x01, 0x8c, 0x04, 0x28, 0x01, 0x8e, + 0x04, 0x29, 0x01, 0xdf, 0xb6, 0xa9, 0xec, 0x1b, + 0xdf, 0xe0, 0xeb, 0xad, 0xec, 0x0c, 0xe0, 0x43, + 0xa3, 0x01, 0x00, 0x00, 0xe1, 0x24, 0x01, 0x00, + 0x0e, 0xdf, 0x8f, 0xe3, 0xe0, 0xdf, 0x48, 0xe9, + 0xeb, 0xe6, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xe4, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x04, 0x00, 0x12, + 0x00, 0xf6, 0x03, 0x1d, 0x01, 0xf4, 0x03, 0x1c, + 0x01, 0x8c, 0x04, 0x28, 0x01, 0x8e, 0x04, 0x29, + 0x01, 0xdf, 0xe0, 0xeb, 0xb7, 0x9f, 0xa7, 0xec, + 0x0a, 0xdf, 0x90, 0xe3, 0xe0, 0xdf, 0x48, 0xe9, + 0xeb, 0xe6, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xe6, + 0x04, 0x01, 0x03, 0x01, 0x05, 0x04, 0x00, 0x3d, + 0x04, 0xc8, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, + 0x00, 0x00, 0x00, 0xe8, 0x05, 0x00, 0x01, 0x00, + 0xb0, 0x01, 0x00, 0x02, 0x00, 0x8e, 0x04, 0x29, + 0x01, 0xf4, 0x03, 0x1c, 0x01, 0xf6, 0x03, 0x1d, + 0x01, 0x8c, 0x04, 0x28, 0x01, 0xdf, 0xcb, 0xb7, + 0xcc, 0xc8, 0xe0, 0xeb, 0xa8, 0xec, 0x33, 0xe0, + 0xeb, 0xc8, 0xd3, 0x9b, 0x9e, 0xe1, 0x9e, 0xe0, + 0xeb, 0x9d, 0xcd, 0xe0, 0xc9, 0x48, 0x43, 0x90, + 0x01, 0x00, 0x00, 0xb6, 0xc7, 0x24, 0x02, 0x00, + 0xe2, 0x43, 0x90, 0x01, 0x00, 0x00, 0xb6, 0xc7, + 0x24, 0x02, 0x00, 0xad, 0xec, 0x08, 0xc9, 0xe5, + 0xe0, 0xc9, 0x48, 0xe6, 0x29, 0x94, 0x01, 0xee, + 0xc9, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xe8, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, 0x00, + 0xe6, 0x04, 0x55, 0x01, 0xdf, 0xb5, 0x23, 0x01, + 0x00, 0x0c, 0x43, 0x02, 0x01, 0xea, 0x04, 0x00, + 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, 0x00, 0xe6, + 0x04, 0x55, 0x01, 0xdf, 0xb7, 0x23, 0x01, 0x00, + 0x0c, 0x43, 0x02, 0x01, 0xec, 0x04, 0x01, 0x02, + 0x01, 0x04, 0x05, 0x00, 0x65, 0x03, 0xc8, 0x06, + 0x00, 0x01, 0x00, 0x94, 0x06, 0x00, 0x00, 0x00, + 0xca, 0x06, 0x00, 0x01, 0x00, 0x8e, 0x04, 0x29, + 0x01, 0xb8, 0x04, 0x3e, 0x01, 0x8c, 0x04, 0x28, + 0x01, 0x96, 0x04, 0x2d, 0x01, 0xfc, 0x04, 0x60, + 0x01, 0xdf, 0xcb, 0xd3, 0xb6, 0xa7, 0xec, 0x15, + 0x93, 0x00, 0xe0, 0xe1, 0x43, 0x9f, 0x01, 0x00, + 0x00, 0xc7, 0x24, 0x01, 0x00, 0xf1, 0xec, 0x05, + 0x93, 0x00, 0xee, 0xef, 0xc7, 0xb7, 0x9e, 0xcc, + 0xe0, 0xe1, 0x43, 0x9f, 0x01, 0x00, 0x00, 0xc8, + 0x24, 0x01, 0x00, 0xf1, 0xec, 0x05, 0x94, 0x01, + 0xee, 0xef, 0xc7, 0xb6, 0xaa, 0xec, 0x2f, 0xc7, + 0xe1, 0xeb, 0xa7, 0xec, 0x29, 0xe2, 0x5f, 0x04, + 0x00, 0xaf, 0xec, 0x09, 0x5f, 0x04, 0x00, 0xc6, + 0xd3, 0xf3, 0x0e, 0x29, 0xe1, 0x43, 0x90, 0x01, + 0x00, 0x00, 0xb6, 0xc7, 0x24, 0x02, 0x00, 0xe1, + 0x43, 0x90, 0x01, 0x00, 0x00, 0xc8, 0x24, 0x01, + 0x00, 0x9e, 0xe5, 0xc7, 0xe3, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0xee, 0x04, 0x00, 0x00, 0x00, 0x02, + 0x01, 0x00, 0x04, 0x00, 0xec, 0x04, 0x58, 0x01, + 0xdf, 0xb7, 0xf1, 0x29, 0x0c, 0x43, 0x02, 0x01, + 0xf0, 0x04, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, + 0x1f, 0x00, 0x8c, 0x04, 0x28, 0x01, 0xce, 0x03, + 0x00, 0x0c, 0xec, 0x04, 0x58, 0x01, 0xdf, 0xeb, + 0xb6, 0xad, 0xec, 0x15, 0x66, 0x01, 0x00, 0x43, + 0x8e, 0x01, 0x00, 0x00, 0x04, 0x95, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0xbe, 0xfd, 0x28, + 0xe1, 0xb7, 0xf1, 0x0e, 0x29, 0x0c, 0x43, 0x02, + 0x01, 0xf2, 0x04, 0x00, 0x00, 0x00, 0x02, 0x01, + 0x00, 0x04, 0x00, 0xec, 0x04, 0x58, 0x01, 0xdf, + 0xb5, 0xf1, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xf4, + 0x04, 0x00, 0x01, 0x00, 0x06, 0x02, 0x00, 0x51, + 0x01, 0xc0, 0x06, 0x00, 0x00, 0x00, 0x8e, 0x04, + 0x29, 0x01, 0x8c, 0x04, 0x28, 0x01, 0xdf, 0xcb, + 0xe0, 0xeb, 0xb7, 0xa9, 0xec, 0x49, 0xc7, 0xb6, + 0xa9, 0xec, 0x44, 0xc7, 0xe0, 0xeb, 0xad, 0xec, + 0x03, 0x93, 0x00, 0xe0, 0x43, 0x90, 0x01, 0x00, + 0x00, 0xb6, 0xc7, 0xb7, 0x9f, 0x24, 0x02, 0x00, + 0xe0, 0x43, 0x90, 0x01, 0x00, 0x00, 0xc7, 0xc7, + 0xb7, 0x9e, 0x24, 0x02, 0x00, 0x9e, 0xe0, 0x43, + 0x90, 0x01, 0x00, 0x00, 0xc7, 0xb7, 0x9f, 0xc7, + 0x24, 0x02, 0x00, 0x9e, 0xe0, 0x43, 0x90, 0x01, + 0x00, 0x00, 0xc7, 0xb7, 0x9e, 0x24, 0x01, 0x00, + 0x9e, 0xe4, 0xc7, 0xb7, 0x9e, 0xe3, 0x29, 0x0c, + 0x43, 0x02, 0x01, 0xf6, 0x04, 0x00, 0x04, 0x00, + 0x05, 0x04, 0x00, 0x55, 0x04, 0xcc, 0x06, 0x00, + 0x00, 0x00, 0xce, 0x06, 0x00, 0x01, 0x00, 0xd0, + 0x06, 0x00, 0x02, 0x00, 0xd2, 0x06, 0x00, 0x03, + 0x00, 0xd6, 0x04, 0x4d, 0x01, 0x8e, 0x04, 0x29, + 0x01, 0xd4, 0x04, 0x4c, 0x01, 0x8c, 0x04, 0x28, + 0x01, 0xdf, 0xe0, 0xf1, 0xcb, 0xe1, 0xc7, 0xf1, + 0xcc, 0xe1, 0xe0, 0xf1, 0xcd, 0xdf, 0xc9, 0xf1, + 0xce, 0xc6, 0xa7, 0xec, 0x41, 0xc8, 0xe0, 0xa8, + 0xec, 0x3c, 0xe0, 0xca, 0xa8, 0xec, 0x37, 0xca, + 0xc9, 0xa7, 0xec, 0x32, 0xe2, 0x43, 0x90, 0x01, + 0x00, 0x00, 0xb6, 0xc7, 0x24, 0x02, 0x00, 0xe2, + 0x43, 0x90, 0x01, 0x00, 0x00, 0xca, 0xc9, 0x24, + 0x02, 0x00, 0x9e, 0xe2, 0x43, 0x90, 0x01, 0x00, + 0x00, 0xc8, 0xca, 0x24, 0x02, 0x00, 0x9e, 0xe2, + 0x43, 0x90, 0x01, 0x00, 0x00, 0xc6, 0x24, 0x02, + 0x00, 0x9e, 0xe6, 0xc9, 0xe4, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0xf8, 0x04, 0x00, 0x01, 0x00, 0x05, + 0x03, 0x00, 0x30, 0x01, 0xca, 0x06, 0x00, 0x00, + 0x00, 0xd4, 0x04, 0x4c, 0x01, 0x8e, 0x04, 0x29, + 0x01, 0x8c, 0x04, 0x28, 0x01, 0xdf, 0xe0, 0xf1, + 0xcb, 0xe1, 0x43, 0x90, 0x01, 0x00, 0x00, 0xb6, + 0xe0, 0x24, 0x02, 0x00, 0xe1, 0x43, 0x90, 0x01, + 0x00, 0x00, 0xe0, 0xc7, 0x24, 0x02, 0x00, 0x43, + 0xaa, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9e, + 0xe1, 0x43, 0x90, 0x01, 0x00, 0x00, 0xc7, 0x24, + 0x01, 0x00, 0x9e, 0xe5, 0x29, 0x0c, 0x43, 0x02, + 0x01, 0xfa, 0x04, 0x00, 0x01, 0x00, 0x05, 0x03, + 0x00, 0x30, 0x01, 0xca, 0x06, 0x00, 0x00, 0x00, + 0xd4, 0x04, 0x4c, 0x01, 0x8e, 0x04, 0x29, 0x01, + 0x8c, 0x04, 0x28, 0x01, 0xdf, 0xe0, 0xf1, 0xcb, + 0xe1, 0x43, 0x90, 0x01, 0x00, 0x00, 0xb6, 0xe0, + 0x24, 0x02, 0x00, 0xe1, 0x43, 0x90, 0x01, 0x00, + 0x00, 0xe0, 0xc7, 0x24, 0x02, 0x00, 0x43, 0xab, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9e, 0xe1, + 0x43, 0x90, 0x01, 0x00, 0x00, 0xc7, 0x24, 0x01, + 0x00, 0x9e, 0xe5, 0x29, 0x0c, 0x43, 0x02, 0x01, + 0xfc, 0x04, 0x03, 0x01, 0x03, 0x04, 0x06, 0x00, + 0x5e, 0x04, 0x94, 0x06, 0x00, 0x01, 0x00, 0xca, + 0x06, 0x00, 0x01, 0x00, 0xc8, 0x06, 0x00, 0x01, + 0x00, 0xd8, 0x06, 0x00, 0x00, 0x00, 0x8c, 0x04, + 0x28, 0x01, 0x96, 0x04, 0x2d, 0x01, 0xfc, 0x04, + 0x60, 0x01, 0xf8, 0x03, 0x1e, 0x01, 0x8e, 0x04, + 0x29, 0x01, 0x94, 0x04, 0x2c, 0x01, 0xdf, 0x43, + 0x90, 0x01, 0x00, 0x00, 0xd3, 0xd4, 0x24, 0x02, + 0x00, 0xcb, 0xe0, 0xe1, 0xb0, 0xec, 0x05, 0xc7, + 0xe6, 0xee, 0x10, 0xd5, 0xb6, 0xa7, 0xec, 0x07, + 0xc7, 0xe2, 0x9e, 0xe6, 0xee, 0x05, 0xe2, 0xc7, + 0x9e, 0xe6, 0xdf, 0x43, 0x90, 0x01, 0x00, 0x00, + 0xb6, 0xd3, 0x24, 0x02, 0x00, 0xdf, 0x43, 0x90, + 0x01, 0x00, 0x00, 0xd4, 0x24, 0x01, 0x00, 0x9e, + 0xe3, 0x5f, 0x04, 0x00, 0xd4, 0xa9, 0xec, 0x0d, + 0x5f, 0x04, 0x00, 0xd4, 0xd3, 0x9f, 0x9f, 0x60, + 0x04, 0x00, 0xee, 0x0c, 0x5f, 0x04, 0x00, 0xd3, + 0xa9, 0xec, 0x05, 0xd3, 0x60, 0x04, 0x00, 0xe1, + 0x60, 0x05, 0x00, 0x29, 0x0c, 0x43, 0x02, 0x01, + 0xfe, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x07, 0x00, 0xfc, 0x04, 0x60, 0x01, 0x8e, 0x04, + 0x29, 0x01, 0x8c, 0x04, 0x28, 0x01, 0xdf, 0xe0, + 0xe1, 0xeb, 0xb7, 0xf3, 0x29, 0x0c, 0x43, 0x02, + 0x01, 0x80, 0x05, 0x00, 0x00, 0x00, 0x04, 0x02, + 0x00, 0x06, 0x00, 0xfc, 0x04, 0x60, 0x01, 0x8e, + 0x04, 0x29, 0x01, 0xdf, 0xb6, 0xe0, 0xb5, 0xf3, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0x82, 0x05, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x08, 0x00, 0xfc, + 0x04, 0x60, 0x01, 0x8e, 0x04, 0x29, 0x01, 0xd4, + 0x04, 0x4c, 0x01, 0xdf, 0xe0, 0xe1, 0xe0, 0xf1, + 0xb7, 0xf3, 0x29, 0x0c, 0x43, 0x02, 0x01, 0x84, + 0x05, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x08, + 0x00, 0xfc, 0x04, 0x60, 0x01, 0xd6, 0x04, 0x4d, + 0x01, 0x8e, 0x04, 0x29, 0x01, 0xdf, 0xe0, 0xe1, + 0xf1, 0xe1, 0xb5, 0xf3, 0x29, 0x0c, 0x43, 0x02, + 0x01, 0x86, 0x05, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x00, 0x04, 0x00, 0xc4, 0x04, 0x44, 0x01, 0xf8, + 0x03, 0x1e, 0x01, 0xdf, 0xe0, 0xf1, 0x29, 0x0c, + 0x43, 0x02, 0x01, 0x88, 0x05, 0x00, 0x00, 0x00, + 0x03, 0x05, 0x00, 0x32, 0x00, 0x96, 0x04, 0x2d, + 0x01, 0x88, 0x05, 0x66, 0x01, 0xce, 0x03, 0x00, + 0x0c, 0xb6, 0x05, 0x7d, 0x01, 0xa0, 0x05, 0x72, + 0x01, 0xdf, 0xe0, 0xaf, 0xec, 0x17, 0x66, 0x02, + 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, 0x04, 0x95, + 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xe2, + 0xb6, 0xf1, 0x0e, 0x29, 0x66, 0x02, 0x00, 0x43, + 0x8e, 0x01, 0x00, 0x00, 0x04, 0xad, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0x5f, 0x04, 0x00, + 0xf0, 0x0e, 0x29, 0x0c, 0x43, 0x02, 0x01, 0x8a, + 0x05, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x05, + 0x00, 0x8c, 0x04, 0x28, 0x01, 0x8e, 0x04, 0x29, + 0x01, 0xc2, 0xe3, 0xb6, 0xe4, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0x8c, 0x05, 0x02, 0x01, 0x02, 0x04, + 0x02, 0x00, 0x39, 0x03, 0xdc, 0x06, 0x00, 0x01, + 0x00, 0xca, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, + 0x00, 0x00, 0x00, 0xb2, 0x04, 0x3b, 0x01, 0xb4, + 0x04, 0x3c, 0x01, 0xd4, 0xcb, 0xc7, 0xb6, 0xa9, + 0xec, 0x0e, 0xdf, 0xd3, 0xc7, 0xb7, 0x9f, 0x48, + 0xf1, 0xec, 0x05, 0x93, 0x00, 0xee, 0xef, 0xc7, + 0xb6, 0xa9, 0xec, 0x0e, 0xe0, 0xd3, 0xc7, 0xb7, + 0x9f, 0x48, 0xf1, 0xec, 0x05, 0x93, 0x00, 0xee, + 0xef, 0xc7, 0xb6, 0xa9, 0x11, 0xec, 0x0d, 0x0e, + 0xd3, 0xc7, 0xb7, 0x9f, 0x48, 0x04, 0xaf, 0x01, + 0x00, 0x00, 0xaf, 0x28, 0x0c, 0x43, 0x02, 0x01, + 0x8e, 0x05, 0x02, 0x01, 0x02, 0x04, 0x01, 0x00, + 0x1f, 0x03, 0xdc, 0x06, 0x00, 0x01, 0x00, 0xca, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x00, + 0x00, 0xb2, 0x04, 0x3b, 0x01, 0xd4, 0xcb, 0xc7, + 0xb6, 0xa9, 0xec, 0x0e, 0xdf, 0xd3, 0xc7, 0xb7, + 0x9f, 0x48, 0xf1, 0xec, 0x05, 0x93, 0x00, 0xee, + 0xef, 0xd3, 0x43, 0xb0, 0x01, 0x00, 0x00, 0xc7, + 0xd4, 0x25, 0x02, 0x00, 0x0c, 0x43, 0x02, 0x01, + 0x90, 0x05, 0x02, 0x04, 0x02, 0x05, 0x07, 0x04, + 0x9f, 0x02, 0x06, 0xdc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xee, 0x05, 0x00, + 0x00, 0x00, 0xe2, 0x06, 0x00, 0x01, 0x00, 0xe4, + 0x06, 0x00, 0x02, 0x00, 0xe6, 0x06, 0x00, 0x03, + 0x00, 0xd4, 0x03, 0x00, 0x03, 0xba, 0x05, 0x7f, + 0x01, 0xb2, 0x04, 0x3b, 0x01, 0x8e, 0x05, 0x69, + 0x01, 0xd8, 0x03, 0x0e, 0x01, 0x90, 0x05, 0x6a, + 0x01, 0xc4, 0x02, 0x08, 0x01, 0x07, 0x02, 0x20, + 0x07, 0x34, 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, + 0x00, 0x00, 0x09, 0x06, 0x00, 0x00, 0x00, 0x05, + 0x08, 0xf5, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x01, + 0x20, 0x0d, 0x00, 0x0b, 0x07, 0x1a, 0x5e, 0x5b, + 0x64, 0x67, 0x69, 0x6d, 0x73, 0x75, 0x76, 0x79, + 0x5d, 0x2b, 0x24, 0x07, 0x96, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x43, 0x00, 0x00, 0x00, 0x09, 0x06, + 0x00, 0x00, 0x00, 0x05, 0x08, 0xf5, 0xff, 0xff, + 0xff, 0x0c, 0x00, 0x06, 0x1d, 0x20, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x7f, 0x01, 0x00, 0x00, 0x00, 0x16, 0x07, 0x00, + 0x64, 0x00, 0x64, 0x00, 0x67, 0x00, 0x67, 0x00, + 0x69, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6d, 0x00, + 0x73, 0x00, 0x73, 0x00, 0x75, 0x00, 0x76, 0x00, + 0x79, 0x00, 0x79, 0x00, 0x0b, 0x07, 0x0d, 0x00, + 0x0b, 0xd4, 0xb6, 0xa8, 0xec, 0x03, 0xdf, 0x28, + 0xd3, 0xd4, 0xb7, 0x9f, 0x48, 0xcb, 0xd4, 0xb7, + 0xaf, 0xec, 0x17, 0xc7, 0x04, 0xb4, 0x01, 0x00, + 0x00, 0xaf, 0x11, 0xed, 0x09, 0x0e, 0xc7, 0x04, + 0xaf, 0x01, 0x00, 0x00, 0xaf, 0xec, 0x03, 0xe0, + 0x28, 0x04, 0xb5, 0x01, 0x00, 0x00, 0x43, 0xb6, + 0x01, 0x00, 0x00, 0xc7, 0x24, 0x01, 0x00, 0xb6, + 0xaa, 0xec, 0x02, 0x29, 0xc7, 0x04, 0xaf, 0x01, + 0x00, 0x00, 0xaf, 0x6a, 0xda, 0x00, 0x00, 0x00, + 0xd4, 0x8f, 0xd8, 0xd3, 0xd4, 0xb7, 0x9f, 0x48, + 0xcf, 0x11, 0x04, 0xb7, 0x01, 0x00, 0x00, 0xaf, + 0xed, 0x13, 0x11, 0x04, 0xb8, 0x01, 0x00, 0x00, + 0xaf, 0xed, 0x0a, 0x11, 0x04, 0xb9, 0x01, 0x00, + 0x00, 0xaf, 0xec, 0x07, 0x04, 0x7a, 0x01, 0x00, + 0x00, 0x28, 0x11, 0x04, 0xba, 0x01, 0x00, 0x00, + 0xaf, 0xec, 0x05, 0x26, 0x00, 0x00, 0x28, 0x11, + 0x04, 0xbb, 0x01, 0x00, 0x00, 0xaf, 0xec, 0x07, + 0xc0, 0x00, 0xc0, 0x01, 0x34, 0x28, 0xe1, 0xc7, + 0xf1, 0x6a, 0x89, 0x00, 0x00, 0x00, 0xe2, 0xd3, + 0xd4, 0xf2, 0xcc, 0xd4, 0xc8, 0xeb, 0x9f, 0xcd, + 0xc8, 0x04, 0x03, 0x00, 0x00, 0x00, 0xaf, 0x11, + 0xed, 0x09, 0x0e, 0xc8, 0x04, 0x02, 0x00, 0x00, + 0x00, 0xaf, 0xec, 0x03, 0x0a, 0x28, 0xc8, 0x04, + 0x01, 0x00, 0x00, 0x00, 0xaf, 0xec, 0x03, 0x07, + 0x28, 0xc8, 0x04, 0x08, 0x00, 0x00, 0x00, 0xaf, + 0xec, 0x03, 0xdf, 0x28, 0x5f, 0x04, 0x00, 0xc8, + 0x8e, 0xf1, 0x97, 0xec, 0x03, 0xb6, 0x28, 0x5f, + 0x05, 0x00, 0xd3, 0xc9, 0xf2, 0xd2, 0xf5, 0x11, + 0xed, 0x04, 0x0e, 0xca, 0xf4, 0xec, 0x03, 0xca, + 0x28, 0xca, 0xc8, 0x48, 0xf6, 0xed, 0x05, 0xca, + 0xc8, 0x48, 0x28, 0xc9, 0xb9, 0xaa, 0xec, 0x24, + 0xd3, 0xc9, 0xb7, 0x9f, 0x48, 0x04, 0xbb, 0x01, + 0x00, 0x00, 0xaf, 0xec, 0x17, 0xc8, 0x43, 0xbc, + 0x01, 0x00, 0x00, 0xc0, 0x02, 0xc0, 0x03, 0x34, + 0x24, 0x01, 0x00, 0xec, 0x07, 0x5f, 0x06, 0x00, + 0x23, 0x00, 0x00, 0x0e, 0x0b, 0x28, 0xdf, 0x28, + 0x0c, 0x43, 0x02, 0x01, 0x92, 0x05, 0x02, 0x0b, + 0x02, 0x06, 0x05, 0x01, 0xa3, 0x02, 0x0d, 0xdc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd8, 0x06, 0x00, 0x00, 0x00, 0xe6, 0x06, + 0x00, 0x01, 0x00, 0xfa, 0x06, 0x00, 0x02, 0x00, + 0xfc, 0x06, 0x00, 0x03, 0x00, 0xe8, 0x05, 0x00, + 0x04, 0x00, 0x98, 0x06, 0x00, 0x05, 0x00, 0xfe, + 0x06, 0x00, 0x06, 0x00, 0x80, 0x07, 0x04, 0x00, + 0x30, 0x82, 0x07, 0x00, 0x07, 0x00, 0x84, 0x07, + 0x00, 0x09, 0x00, 0x86, 0x07, 0x0d, 0x00, 0x21, + 0x8e, 0x05, 0x69, 0x01, 0x90, 0x05, 0x6a, 0x01, + 0x8c, 0x05, 0x68, 0x01, 0xde, 0x03, 0x11, 0x01, + 0xa8, 0x02, 0x00, 0x01, 0x0c, 0x43, 0x02, 0x01, + 0x86, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, + 0x34, 0x02, 0xf4, 0x05, 0x00, 0x01, 0x00, 0x8c, + 0x06, 0x00, 0x01, 0x00, 0xd3, 0xb6, 0x48, 0xd4, + 0xb6, 0x48, 0xae, 0xec, 0x1b, 0xd3, 0xb6, 0x48, + 0x04, 0x7c, 0x01, 0x00, 0x00, 0xad, 0xec, 0x03, + 0xb7, 0x28, 0xd4, 0xb6, 0x48, 0x04, 0x7c, 0x01, + 0x00, 0x00, 0xad, 0xec, 0x03, 0xb5, 0x28, 0xd3, + 0xd4, 0xa7, 0xec, 0x03, 0xb5, 0x28, 0xd3, 0xd4, + 0xa9, 0xec, 0x04, 0xb7, 0x8e, 0x28, 0xb6, 0x28, + 0xdf, 0xd3, 0xd4, 0xf2, 0xcb, 0xe0, 0xd3, 0xd4, + 0xc7, 0xeb, 0x9f, 0xf2, 0xcd, 0x26, 0x00, 0x00, + 0xce, 0xe1, 0xd3, 0xd4, 0xf2, 0x97, 0xec, 0x2b, + 0x62, 0x07, 0x00, 0xe2, 0x7f, 0xee, 0x1e, 0xc4, + 0x07, 0x63, 0x07, 0x00, 0x43, 0xc4, 0x01, 0x00, + 0x00, 0xc7, 0x24, 0x01, 0x00, 0xec, 0x0e, 0xca, + 0x43, 0xa3, 0x01, 0x00, 0x00, 0x63, 0x07, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0x82, 0x00, 0xec, 0xe0, + 0x0e, 0x85, 0xb6, 0xc4, 0x04, 0xc9, 0xcc, 0xc3, + 0x04, 0xbe, 0x0a, 0xa7, 0xec, 0x6b, 0xc8, 0xf5, + 0xed, 0x67, 0xc8, 0x06, 0xb0, 0xec, 0x62, 0x5f, + 0x04, 0x00, 0x43, 0xc5, 0x01, 0x00, 0x00, 0xc8, + 0x24, 0x01, 0x00, 0xc4, 0x08, 0xb6, 0xc4, 0x05, + 0xc3, 0x05, 0xc3, 0x08, 0xeb, 0xa7, 0xec, 0x38, + 0xc3, 0x08, 0xc3, 0x05, 0x48, 0xc5, 0x09, 0x98, + 0x04, 0x49, 0x00, 0x00, 0x00, 0xad, 0xec, 0x24, + 0xc2, 0xc3, 0x09, 0x8e, 0x9e, 0xc3, 0x09, 0xae, + 0xec, 0x1a, 0xc3, 0x09, 0x43, 0xc4, 0x01, 0x00, + 0x00, 0xc7, 0x24, 0x01, 0x00, 0xec, 0x0d, 0xca, + 0x43, 0xa3, 0x01, 0x00, 0x00, 0xc3, 0x09, 0x24, + 0x01, 0x00, 0x0e, 0x94, 0x05, 0xee, 0xc2, 0x5f, + 0x04, 0x00, 0x43, 0x60, 0x00, 0x00, 0x00, 0xc8, + 0x24, 0x01, 0x00, 0xcc, 0x94, 0x04, 0xee, 0x90, + 0xca, 0xeb, 0xb7, 0xa9, 0xec, 0x51, 0xc1, 0x00, + 0xc4, 0x0a, 0xc1, 0x00, 0x0e, 0xca, 0x43, 0xc6, + 0x01, 0x00, 0x00, 0x63, 0x0a, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0xb7, 0xc5, 0x05, 0xc4, 0x04, 0xc3, + 0x04, 0xca, 0xeb, 0xa7, 0xec, 0x29, 0xca, 0xc3, + 0x04, 0x48, 0xca, 0xc3, 0x04, 0xb7, 0x9f, 0x48, + 0xae, 0xec, 0x18, 0xca, 0xc3, 0x05, 0x92, 0xc4, + 0x05, 0x1b, 0x11, 0xb1, 0xed, 0x04, 0x1b, 0x72, + 0x1b, 0x1b, 0xca, 0xc3, 0x04, 0x48, 0x1b, 0x72, + 0x1b, 0x4a, 0x94, 0x04, 0xee, 0xd2, 0xca, 0xc3, + 0x05, 0x44, 0x32, 0x00, 0x00, 0x00, 0x0b, 0xca, + 0x4d, 0x6b, 0x01, 0x00, 0x00, 0xc7, 0xeb, 0x4d, + 0xa0, 0x01, 0x00, 0x00, 0xc9, 0x4d, 0xc7, 0x01, + 0x00, 0x00, 0x28, 0x0c, 0x43, 0x02, 0x01, 0x94, + 0x05, 0x00, 0x0d, 0x00, 0x07, 0x0a, 0x00, 0xa1, + 0x03, 0x0d, 0xd6, 0x05, 0x00, 0x00, 0x00, 0x90, + 0x07, 0x00, 0x01, 0x00, 0xd8, 0x06, 0x00, 0x02, + 0x00, 0xe8, 0x05, 0x00, 0x03, 0x00, 0x98, 0x06, + 0x00, 0x04, 0x00, 0x82, 0x06, 0x00, 0x05, 0x00, + 0x92, 0x07, 0x00, 0x06, 0x00, 0x94, 0x07, 0x00, + 0x07, 0x00, 0x96, 0x07, 0x00, 0x08, 0x00, 0x98, + 0x07, 0x00, 0x09, 0x00, 0x9a, 0x07, 0x00, 0x0a, + 0x00, 0x9c, 0x07, 0x00, 0x0b, 0x00, 0x9e, 0x07, + 0x00, 0x0c, 0x00, 0x92, 0x05, 0x6b, 0x01, 0x8c, + 0x04, 0x28, 0x01, 0x8e, 0x04, 0x29, 0x01, 0xc4, + 0x04, 0x44, 0x01, 0x96, 0x04, 0x2d, 0x01, 0x94, + 0x05, 0x6c, 0x01, 0xb8, 0x02, 0x0b, 0x01, 0xa2, + 0x04, 0x33, 0x01, 0xce, 0x03, 0x00, 0x0c, 0xa0, + 0x05, 0x72, 0x01, 0xdf, 0xe0, 0xe1, 0xf2, 0xd0, + 0x42, 0x6b, 0x01, 0x00, 0x00, 0xcf, 0xeb, 0xb6, + 0xaf, 0xec, 0x02, 0x29, 0xc7, 0xb6, 0x48, 0xd1, + 0xeb, 0xc4, 0x05, 0xb7, 0xce, 0xca, 0xc7, 0xeb, + 0xa7, 0xec, 0x2a, 0xc7, 0xca, 0x48, 0xc4, 0x06, + 0xb6, 0xc4, 0x04, 0xc3, 0x04, 0xc3, 0x05, 0xa7, + 0xec, 0x17, 0xc3, 0x06, 0xc3, 0x04, 0x48, 0xc9, + 0xc3, 0x04, 0x48, 0xb0, 0xec, 0x07, 0xc3, 0x04, + 0xc4, 0x05, 0xee, 0x05, 0x94, 0x04, 0xee, 0xe4, + 0x94, 0x03, 0xee, 0xd2, 0xc8, 0x42, 0xa0, 0x01, + 0x00, 0x00, 0xce, 0xca, 0xc3, 0x05, 0xa7, 0xec, + 0x0b, 0xe2, 0xc9, 0xca, 0x48, 0xf1, 0x0e, 0x94, + 0x03, 0xee, 0xf1, 0x5f, 0x04, 0x00, 0x5f, 0x05, + 0x00, 0xaf, 0xec, 0x54, 0xc7, 0xeb, 0xb7, 0xad, + 0xec, 0x4e, 0xc7, 0xb6, 0x48, 0xcd, 0xc8, 0x42, + 0xc7, 0x01, 0x00, 0x00, 0xc9, 0x48, 0xc5, 0x0c, + 0xf7, 0xec, 0x1a, 0xe2, 0x04, 0xd0, 0x01, 0x00, + 0x00, 0xf1, 0x0e, 0xc3, 0x0c, 0xeb, 0xb6, 0xad, + 0xec, 0x2e, 0xe2, 0x04, 0xd1, 0x01, 0x00, 0x00, + 0xf1, 0x0e, 0xee, 0x24, 0xc3, 0x0c, 0x98, 0x04, + 0x4a, 0x00, 0x00, 0x00, 0xad, 0x11, 0xed, 0x0e, + 0x0e, 0xc3, 0x0c, 0xf6, 0xec, 0x12, 0xc9, 0x04, + 0x08, 0x00, 0x00, 0x00, 0xad, 0xec, 0x09, 0xe2, + 0x04, 0xaf, 0x01, 0x00, 0x00, 0xf1, 0x0e, 0x5f, + 0x04, 0x00, 0x5f, 0x05, 0x00, 0xaf, 0x6a, 0xdc, + 0x00, 0x00, 0x00, 0xc7, 0xeb, 0xb8, 0xaa, 0x6a, + 0xd3, 0x00, 0x00, 0x00, 0xb6, 0xc4, 0x07, 0xb6, + 0xce, 0xca, 0xc7, 0xeb, 0xa7, 0xec, 0x18, 0x5f, + 0x06, 0x00, 0x43, 0xd2, 0x01, 0x00, 0x00, 0xc3, + 0x07, 0xc7, 0xca, 0x48, 0xeb, 0x24, 0x02, 0x00, + 0xc4, 0x07, 0x94, 0x03, 0xee, 0xe4, 0xb8, 0x95, + 0x07, 0x5f, 0x06, 0x00, 0x43, 0xd2, 0x01, 0x00, + 0x00, 0xb7, 0x5f, 0x06, 0x00, 0x43, 0xd3, 0x01, + 0x00, 0x00, 0x5f, 0x07, 0x00, 0xb7, 0x9e, 0xc3, + 0x07, 0x9c, 0x24, 0x01, 0x00, 0x24, 0x02, 0x00, + 0xc4, 0x09, 0x5f, 0x06, 0x00, 0x43, 0xd4, 0x01, + 0x00, 0x00, 0xc7, 0xeb, 0xc3, 0x09, 0x9c, 0x24, + 0x01, 0x00, 0xc4, 0x0b, 0x66, 0x08, 0x00, 0x43, + 0x8e, 0x01, 0x00, 0x00, 0x04, 0x95, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0xb6, 0xc4, 0x0a, + 0xc3, 0x0a, 0xc3, 0x0b, 0xa7, 0xec, 0x58, 0xb6, + 0xc4, 0x08, 0xc3, 0x08, 0xc3, 0x09, 0xa7, 0xec, + 0x39, 0xc3, 0x08, 0xc3, 0x0b, 0x9b, 0xc3, 0x0a, + 0x9e, 0xd2, 0xc7, 0xeb, 0xaa, 0xed, 0x2b, 0xc7, + 0xca, 0x48, 0xcd, 0xc3, 0x08, 0xc3, 0x09, 0xb7, + 0x9f, 0xae, 0xec, 0x0d, 0xc9, 0x43, 0xd5, 0x01, + 0x00, 0x00, 0xc3, 0x07, 0x24, 0x01, 0x00, 0xcd, + 0x66, 0x08, 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, + 0xc9, 0x24, 0x01, 0x00, 0x0e, 0x94, 0x08, 0xee, + 0xc2, 0x66, 0x08, 0x00, 0x43, 0x8e, 0x01, 0x00, + 0x00, 0x04, 0x95, 0x01, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0x94, 0x0a, 0xee, 0xa3, 0x5f, 0x09, + 0x00, 0xf0, 0x0e, 0x29, 0x0c, 0x43, 0x02, 0x01, + 0x98, 0x05, 0x02, 0x01, 0x02, 0x02, 0x00, 0x00, + 0x10, 0x03, 0x80, 0x06, 0x00, 0x01, 0x00, 0xac, + 0x07, 0x00, 0x01, 0x00, 0x90, 0x07, 0x00, 0x00, + 0x00, 0xc2, 0xcb, 0xd4, 0x91, 0xd8, 0xb6, 0xa9, + 0xec, 0x06, 0xd3, 0x95, 0x00, 0xee, 0xf5, 0xc7, + 0x28, 0x0c, 0x43, 0x02, 0x01, 0xa0, 0x05, 0x00, + 0x00, 0x00, 0x03, 0x07, 0x00, 0x1e, 0x00, 0xce, + 0x03, 0x00, 0x0c, 0xfc, 0x03, 0x20, 0x01, 0xa4, + 0x04, 0x34, 0x01, 0xb6, 0x04, 0x3d, 0x01, 0xa2, + 0x04, 0x33, 0x01, 0x90, 0x04, 0x2a, 0x01, 0x92, + 0x04, 0x2b, 0x01, 0x66, 0x00, 0x00, 0x43, 0x8e, + 0x01, 0x00, 0x00, 0xe0, 0x24, 0x01, 0x00, 0x0e, + 0xe2, 0xe0, 0xf1, 0x5f, 0x04, 0x00, 0x9d, 0xe5, + 0xc2, 0x60, 0x05, 0x00, 0xb6, 0x60, 0x06, 0x00, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xa2, 0x05, 0x02, + 0x01, 0x02, 0x05, 0x11, 0x00, 0x80, 0x01, 0x03, + 0xae, 0x07, 0x00, 0x01, 0x00, 0xb0, 0x07, 0x00, + 0x01, 0x00, 0x92, 0x07, 0x00, 0x00, 0x00, 0x8c, + 0x04, 0x28, 0x01, 0x8e, 0x04, 0x29, 0x01, 0xf6, + 0x03, 0x1d, 0x01, 0xf4, 0x03, 0x1c, 0x01, 0x9e, + 0x05, 0x71, 0x01, 0xfc, 0x03, 0x20, 0x01, 0xfa, + 0x03, 0x1f, 0x01, 0x88, 0x04, 0x26, 0x01, 0x98, + 0x05, 0x6e, 0x01, 0xfe, 0x03, 0x21, 0x01, 0x82, + 0x04, 0x23, 0x01, 0xe8, 0x03, 0x16, 0x01, 0x86, + 0x04, 0x25, 0x01, 0x80, 0x04, 0x22, 0x01, 0xa0, + 0x05, 0x72, 0x01, 0xc2, 0x04, 0x43, 0x01, 0x9c, + 0x05, 0x70, 0x01, 0xd3, 0x11, 0xed, 0x03, 0x0e, + 0xc2, 0xe7, 0xeb, 0xe4, 0xe2, 0xeb, 0xe5, 0xd4, + 0x60, 0x04, 0x00, 0x5f, 0x06, 0x00, 0x60, 0x05, + 0x00, 0x5f, 0x07, 0x00, 0xec, 0x22, 0x5f, 0x05, + 0x00, 0x5f, 0x08, 0x00, 0x04, 0xd9, 0x01, 0x00, + 0x00, 0x5f, 0x09, 0x00, 0x5f, 0x05, 0x00, 0xeb, + 0x9f, 0xf2, 0x9e, 0x61, 0x05, 0x00, 0x5f, 0x0a, + 0x00, 0x9e, 0x60, 0x05, 0x00, 0xee, 0x36, 0x5f, + 0x0b, 0x00, 0xec, 0x20, 0x5f, 0x0c, 0x00, 0xbf, + 0xe8, 0x03, 0x9c, 0xcb, 0x5f, 0x05, 0x00, 0xc7, + 0x43, 0xda, 0x01, 0x00, 0x00, 0xbc, 0x24, 0x01, + 0x00, 0x04, 0xd9, 0x01, 0x00, 0x00, 0x9e, 0x9e, + 0x60, 0x05, 0x00, 0x5f, 0x05, 0x00, 0xeb, 0x60, + 0x09, 0x00, 0x5f, 0x05, 0x00, 0x5f, 0x0d, 0x00, + 0x9e, 0x60, 0x05, 0x00, 0x5f, 0x0e, 0x00, 0xf0, + 0x0e, 0x5f, 0x0f, 0x00, 0xf0, 0x0e, 0xb6, 0x60, + 0x10, 0x00, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xa4, + 0x05, 0x01, 0x01, 0x01, 0x03, 0x04, 0x02, 0x86, + 0x01, 0x02, 0xb6, 0x07, 0x00, 0x01, 0x00, 0xee, + 0x05, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x01, 0x01, + 0x9c, 0x05, 0x70, 0x01, 0x9a, 0x05, 0x6f, 0x01, + 0xa6, 0x05, 0x75, 0x01, 0x07, 0x02, 0x30, 0x07, + 0x02, 0x39, 0xdf, 0x43, 0xdc, 0x01, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0xcb, 0xe0, 0x11, 0xb6, + 0xaf, 0xec, 0x14, 0xc7, 0x04, 0xdd, 0x01, 0x00, + 0x00, 0xad, 0xec, 0x06, 0xc7, 0xe5, 0xb7, 0xe4, + 0x29, 0xe2, 0xc7, 0xf1, 0x0e, 0x29, 0x11, 0xb7, + 0xaf, 0xec, 0x24, 0xe1, 0xc7, 0x9e, 0xe5, 0xc7, + 0x04, 0xde, 0x01, 0x00, 0x00, 0xad, 0xec, 0x04, + 0xb8, 0xe4, 0x29, 0xc7, 0x04, 0xdf, 0x01, 0x00, + 0x00, 0xad, 0xec, 0x04, 0xb9, 0xe4, 0x29, 0xe2, + 0xe1, 0xf1, 0x0e, 0xb6, 0xe4, 0x29, 0x11, 0xb8, + 0xaf, 0xec, 0x26, 0xe1, 0xc7, 0x9e, 0xe5, 0xc7, + 0x04, 0xe0, 0x01, 0x00, 0x00, 0xad, 0x11, 0xed, + 0x0e, 0x0e, 0xc7, 0xc0, 0x00, 0xaa, 0x11, 0xec, + 0x06, 0x0e, 0xc7, 0xc0, 0x01, 0xa8, 0x97, 0xec, + 0x17, 0xe2, 0xe1, 0xf1, 0x0e, 0xb6, 0xe4, 0x29, + 0x11, 0xb9, 0xaf, 0xec, 0x0b, 0xe1, 0xc7, 0x9e, + 0xe5, 0xe2, 0xe1, 0xf1, 0x0e, 0xb6, 0xe4, 0x29, + 0x0c, 0x43, 0x02, 0x01, 0xa6, 0x05, 0x01, 0x01, + 0x01, 0x05, 0x0e, 0x00, 0xb6, 0x01, 0x02, 0x60, + 0x00, 0x01, 0x00, 0xc2, 0x07, 0x00, 0x00, 0x00, + 0x98, 0x04, 0x2e, 0x01, 0xb6, 0x04, 0x3d, 0x01, + 0xc4, 0x04, 0x44, 0x01, 0x96, 0x05, 0x6d, 0x01, + 0x94, 0x04, 0x2c, 0x01, 0x9e, 0x05, 0x71, 0x01, + 0x8c, 0x04, 0x28, 0x01, 0xd0, 0x03, 0x01, 0x0c, + 0x9e, 0x04, 0x31, 0x01, 0xd0, 0x05, 0x8a, 0x01, + 0x01, 0x96, 0x04, 0x2d, 0x01, 0xca, 0x04, 0x47, + 0x01, 0x8e, 0x04, 0x29, 0x01, 0xc2, 0x04, 0x43, + 0x01, 0xdf, 0xec, 0x11, 0xe0, 0xd3, 0xf1, 0xb7, + 0xaf, 0xec, 0x05, 0xe1, 0xd3, 0xf1, 0x0e, 0x09, + 0xe3, 0xef, 0x80, 0x00, 0xe2, 0xd3, 0x48, 0xcf, + 0xec, 0x5a, 0xc7, 0x60, 0x04, 0x00, 0xc7, 0xd3, + 0xf1, 0x11, 0xb5, 0xaf, 0xec, 0x09, 0x5f, 0x05, + 0x00, 0x5f, 0x06, 0x00, 0xf1, 0x29, 0x11, 0xbe, + 0xfe, 0xaf, 0xec, 0x07, 0x5f, 0x05, 0x00, 0x07, + 0xf1, 0x29, 0x11, 0xbe, 0xfd, 0xaf, 0xec, 0x2b, + 0x66, 0x07, 0x00, 0x43, 0x70, 0x01, 0x00, 0x00, + 0x66, 0x07, 0x00, 0x42, 0x71, 0x01, 0x00, 0x00, + 0x07, 0x24, 0x02, 0x00, 0x0e, 0x66, 0x07, 0x00, + 0x43, 0x72, 0x01, 0x00, 0x00, 0x5f, 0x08, 0x00, + 0x07, 0x24, 0x02, 0x00, 0x0e, 0x5f, 0x09, 0x00, + 0xf0, 0x29, 0x0e, 0x5f, 0x04, 0x00, 0x60, 0x0a, + 0x00, 0xee, 0x20, 0xe0, 0xd3, 0xf1, 0xb7, 0xaf, + 0xec, 0x14, 0xd3, 0x04, 0xd9, 0x01, 0x00, 0x00, + 0xaa, 0xec, 0x0b, 0xe1, 0xd3, 0xf1, 0x0e, 0xe1, + 0x60, 0x0a, 0x00, 0xee, 0x06, 0x5f, 0x0b, 0x00, + 0xf0, 0x0e, 0x5f, 0x0c, 0x00, 0xb6, 0xa7, 0xec, + 0x04, 0xb6, 0xee, 0x14, 0x5f, 0x0c, 0x00, 0x5f, + 0x06, 0x00, 0xeb, 0xa9, 0xec, 0x07, 0x5f, 0x06, + 0x00, 0xeb, 0xee, 0x04, 0x5f, 0x0c, 0x00, 0x60, + 0x0c, 0x00, 0x5f, 0x0d, 0x00, 0xf0, 0x29, 0x0c, + 0x43, 0x02, 0x01, 0xa8, 0x05, 0x02, 0x01, 0x02, + 0x05, 0x02, 0x01, 0x70, 0x03, 0xf4, 0x05, 0x00, + 0x01, 0x00, 0xc4, 0x07, 0x00, 0x01, 0x00, 0xd8, + 0x06, 0x00, 0x00, 0x00, 0xd6, 0x03, 0x0d, 0x01, + 0xb8, 0x02, 0x0b, 0x01, 0x07, 0x02, 0x30, 0xdf, + 0xd3, 0xf1, 0x97, 0xec, 0x0a, 0xd3, 0x43, 0x38, + 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0xd3, 0xb6, + 0xad, 0xec, 0x15, 0xb7, 0xd3, 0x9c, 0xb6, 0xa7, + 0xec, 0x09, 0x04, 0xe3, 0x01, 0x00, 0x00, 0xcb, + 0xee, 0x4c, 0xc0, 0x00, 0xcb, 0xee, 0x47, 0xd4, + 0xbe, 0x10, 0xad, 0xec, 0x37, 0xd3, 0xe0, 0x43, + 0xd3, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0xaf, 0xec, 0x29, 0xd3, 0xb6, 0xa7, 0xec, 0x0c, + 0xd3, 0x8d, 0xd7, 0x04, 0xe4, 0x01, 0x00, 0x00, + 0xcb, 0xee, 0x03, 0xc2, 0xcb, 0xc7, 0x04, 0xe5, + 0x01, 0x00, 0x00, 0xd3, 0x43, 0x38, 0x00, 0x00, + 0x00, 0xbe, 0x10, 0x24, 0x01, 0x00, 0x9e, 0x9e, + 0xcb, 0xee, 0x0b, 0xd3, 0x43, 0x38, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0xcb, 0xc7, 0x28, 0x0c, + 0x43, 0x02, 0x01, 0xaa, 0x05, 0x02, 0x01, 0x02, + 0x05, 0x00, 0x00, 0x40, 0x03, 0xf4, 0x05, 0x00, + 0x01, 0x00, 0xc4, 0x07, 0x00, 0x01, 0x00, 0xd8, + 0x06, 0x00, 0x00, 0x00, 0xd4, 0xbe, 0x10, 0xad, + 0xec, 0x29, 0xd3, 0xb6, 0xa7, 0xec, 0x0c, 0xd3, + 0x8d, 0xd7, 0x04, 0xe4, 0x01, 0x00, 0x00, 0xcb, + 0xee, 0x03, 0xc2, 0xcb, 0xc7, 0x04, 0xe5, 0x01, + 0x00, 0x00, 0xd3, 0x43, 0x38, 0x00, 0x00, 0x00, + 0xbe, 0x10, 0x24, 0x01, 0x00, 0x9e, 0x9e, 0xcb, + 0xee, 0x0b, 0xd3, 0x43, 0x38, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xcb, 0xc7, 0x04, 0x91, 0x01, + 0x00, 0x00, 0x9e, 0x28, 0x0c, 0x43, 0x02, 0x01, + 0x00, 0x04, 0x18, 0x04, 0x06, 0x12, 0x0e, 0xea, + 0x01, 0x1c, 0xcc, 0x07, 0x00, 0x01, 0x00, 0xec, + 0x03, 0x00, 0x01, 0x40, 0xce, 0x07, 0x00, 0x01, + 0x40, 0xd0, 0x07, 0x00, 0x01, 0x40, 0xd2, 0x07, + 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x01, 0x00, + 0xd4, 0x07, 0x00, 0x02, 0x40, 0xd6, 0x07, 0x00, + 0x03, 0x40, 0xd8, 0x07, 0x00, 0x04, 0x40, 0xda, + 0x07, 0x00, 0x05, 0x40, 0xdc, 0x07, 0x00, 0x06, + 0x40, 0x6c, 0x00, 0x07, 0x40, 0xde, 0x07, 0x00, + 0x08, 0x40, 0xe0, 0x07, 0x00, 0x09, 0x40, 0xe2, + 0x07, 0x00, 0x0a, 0x40, 0xe4, 0x07, 0x00, 0x0b, + 0x40, 0xe6, 0x07, 0x00, 0x0c, 0x40, 0xe8, 0x07, + 0x00, 0x0d, 0x40, 0xea, 0x07, 0x00, 0x0e, 0x40, + 0xec, 0x07, 0x00, 0x0f, 0x40, 0xee, 0x07, 0x00, + 0x10, 0x40, 0xf0, 0x07, 0x00, 0x11, 0x40, 0xf2, + 0x07, 0x00, 0x12, 0x40, 0xf4, 0x07, 0x00, 0x13, + 0x40, 0xf6, 0x07, 0x00, 0x14, 0x40, 0xf8, 0x07, + 0x00, 0x15, 0x40, 0xfa, 0x07, 0x00, 0x16, 0x40, + 0xfc, 0x07, 0x00, 0x17, 0x40, 0xda, 0x03, 0x0f, + 0x01, 0xba, 0x02, 0x0c, 0x01, 0xa8, 0x02, 0x00, + 0x01, 0xa8, 0x05, 0x76, 0x01, 0xf0, 0x03, 0x1a, + 0x01, 0xaa, 0x05, 0x77, 0x01, 0xb0, 0x02, 0x01, + 0x01, 0xbc, 0x02, 0x07, 0x01, 0xc4, 0x02, 0x08, + 0x01, 0xb2, 0x02, 0x03, 0x01, 0xae, 0x02, 0x02, + 0x01, 0xe4, 0x02, 0x04, 0x01, 0xaa, 0x02, 0x06, + 0x01, 0xce, 0x02, 0x05, 0x01, 0xe0, 0x03, 0x12, + 0x01, 0xe4, 0x03, 0x14, 0x01, 0xb8, 0x02, 0x0b, + 0x01, 0xa2, 0x04, 0x33, 0x01, 0x0c, 0x43, 0x02, + 0x01, 0x86, 0x01, 0x02, 0x00, 0x02, 0x01, 0x01, + 0x00, 0x0e, 0x02, 0xfe, 0x07, 0x00, 0x01, 0x00, + 0x80, 0x08, 0x00, 0x01, 0x00, 0xda, 0x03, 0x00, + 0x00, 0xd3, 0xf6, 0xec, 0x03, 0xd4, 0x28, 0xd3, + 0xf5, 0xec, 0x03, 0xdf, 0x28, 0xd3, 0x28, 0x0c, + 0x43, 0x02, 0x01, 0xe4, 0x07, 0x01, 0x00, 0x01, + 0x04, 0x01, 0x00, 0x54, 0x01, 0xd8, 0x06, 0x00, + 0x01, 0x00, 0xba, 0x02, 0x01, 0x00, 0xd3, 0x43, + 0x7f, 0x01, 0x00, 0x00, 0x04, 0xb7, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0xec, 0x0b, 0xdf, 0x43, + 0x01, 0x02, 0x00, 0x00, 0xd3, 0x25, 0x01, 0x00, + 0xdf, 0x43, 0x01, 0x02, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0x43, 0xb0, 0x01, 0x00, 0x00, 0xb7, + 0xb5, 0x24, 0x02, 0x00, 0x43, 0x02, 0x02, 0x00, + 0x00, 0x04, 0x03, 0x02, 0x00, 0x00, 0x04, 0xb8, + 0x01, 0x00, 0x00, 0x24, 0x02, 0x00, 0xd7, 0x04, + 0xb7, 0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, + 0x00, 0xd3, 0x04, 0xb7, 0x01, 0x00, 0x00, 0x25, + 0x02, 0x00, 0x0c, 0x43, 0x02, 0x01, 0xe6, 0x07, + 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x0d, 0x01, + 0xd8, 0x06, 0x00, 0x01, 0x00, 0xde, 0x07, 0x08, + 0x01, 0xdf, 0x43, 0xa3, 0x01, 0x00, 0x00, 0xc2, + 0xd3, 0x9e, 0x24, 0x01, 0x00, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0xe8, 0x07, 0x01, 0x00, 0x01, 0x04, + 0x01, 0x00, 0x0c, 0x01, 0xd8, 0x06, 0x00, 0x01, + 0x00, 0xde, 0x07, 0x08, 0x01, 0xdf, 0xdf, 0xeb, + 0xb7, 0x9f, 0x73, 0x13, 0x48, 0xd3, 0x9e, 0x4a, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xea, 0x07, 0x01, + 0x00, 0x01, 0x04, 0x01, 0x00, 0x1f, 0x01, 0x88, + 0x08, 0x00, 0x01, 0x00, 0xa8, 0x02, 0x02, 0x00, + 0xdf, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x38, + 0x00, 0x00, 0x00, 0x43, 0x05, 0x02, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0x43, 0xb0, 0x01, 0x00, + 0x00, 0xbe, 0x08, 0xb5, 0x25, 0x02, 0x00, 0x0c, + 0x43, 0x02, 0x01, 0xec, 0x07, 0x02, 0x13, 0x02, + 0x09, 0x1a, 0x02, 0xdc, 0x0b, 0x15, 0xf4, 0x05, + 0x00, 0x01, 0x00, 0x8a, 0x04, 0x00, 0x01, 0x00, + 0xa2, 0x06, 0x00, 0x00, 0x00, 0x8c, 0x08, 0x00, + 0x01, 0x00, 0xe8, 0x05, 0x00, 0x02, 0x00, 0x8e, + 0x08, 0x00, 0x03, 0x00, 0x60, 0x00, 0x04, 0x00, + 0x90, 0x08, 0x00, 0x05, 0x00, 0x92, 0x08, 0x00, + 0x06, 0x00, 0x94, 0x08, 0x00, 0x07, 0x00, 0x96, + 0x08, 0x00, 0x08, 0x00, 0x98, 0x08, 0x00, 0x09, + 0x00, 0x9a, 0x08, 0x00, 0x0a, 0x00, 0x9c, 0x08, + 0x00, 0x0b, 0x00, 0x9e, 0x08, 0x00, 0x0c, 0x00, + 0xa0, 0x08, 0x00, 0x0d, 0x00, 0xa2, 0x08, 0x00, + 0x0e, 0x00, 0x82, 0x06, 0x00, 0x0f, 0x00, 0x94, + 0x06, 0x00, 0x10, 0x00, 0xa4, 0x08, 0x00, 0x11, + 0x00, 0xa6, 0x08, 0x00, 0x12, 0x00, 0xe6, 0x07, + 0x0c, 0x01, 0xa8, 0x05, 0x03, 0x00, 0xf0, 0x03, + 0x04, 0x00, 0xaa, 0x05, 0x05, 0x00, 0xda, 0x07, + 0x05, 0x01, 0xe4, 0x07, 0x0b, 0x01, 0xb0, 0x02, + 0x06, 0x00, 0xdc, 0x07, 0x06, 0x01, 0x6c, 0x07, + 0x01, 0xde, 0x07, 0x08, 0x01, 0xea, 0x07, 0x0e, + 0x01, 0xbc, 0x02, 0x07, 0x00, 0xba, 0x02, 0x01, + 0x00, 0xc4, 0x02, 0x08, 0x00, 0xb2, 0x02, 0x09, + 0x00, 0xae, 0x02, 0x0a, 0x00, 0xe4, 0x02, 0x0b, + 0x00, 0xaa, 0x02, 0x0c, 0x00, 0xce, 0x02, 0x0d, + 0x00, 0xce, 0x07, 0x02, 0x03, 0xec, 0x07, 0x0f, + 0x01, 0xd6, 0x07, 0x03, 0x01, 0xec, 0x03, 0x01, + 0x03, 0xa8, 0x02, 0x02, 0x00, 0xe8, 0x07, 0x0d, + 0x01, 0xd8, 0x07, 0x04, 0x01, 0x07, 0x32, 0x5e, + 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x5f, + 0x24, 0x5d, 0x5b, 0x30, 0x2d, 0x39, 0x61, 0x2d, + 0x7a, 0x41, 0x2d, 0x5a, 0x5f, 0x24, 0x5d, 0x2a, + 0x07, 0xaa, 0x01, 0x00, 0x00, 0x01, 0x00, 0x4d, + 0x00, 0x00, 0x00, 0x09, 0x06, 0x00, 0x00, 0x00, + 0x05, 0x08, 0xf5, 0xff, 0xff, 0xff, 0x0c, 0x00, + 0x06, 0x16, 0x04, 0x00, 0x24, 0x00, 0x24, 0x00, + 0x41, 0x00, 0x5a, 0x00, 0x5f, 0x00, 0x5f, 0x00, + 0x61, 0x00, 0x7a, 0x00, 0x1d, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x7f, 0x01, 0x00, 0x00, 0x00, 0x16, 0x05, 0x00, + 0x24, 0x00, 0x24, 0x00, 0x30, 0x00, 0x39, 0x00, + 0x41, 0x00, 0x5a, 0x00, 0x5f, 0x00, 0x5f, 0x00, + 0x61, 0x00, 0x7a, 0x00, 0x0b, 0x0d, 0x00, 0x0b, + 0xd3, 0x98, 0xc5, 0x06, 0x11, 0x04, 0x46, 0x00, + 0x00, 0x00, 0xaf, 0xed, 0x0a, 0x11, 0x04, 0x48, + 0x00, 0x00, 0x00, 0xaf, 0xec, 0x06, 0xdf, 0xd3, + 0xf1, 0x0e, 0x29, 0x11, 0x04, 0x47, 0x00, 0x00, + 0x00, 0xaf, 0xec, 0x11, 0xdf, 0xe0, 0xd3, 0xe1, + 0xec, 0x05, 0xbe, 0x10, 0xee, 0x03, 0xbe, 0x0a, + 0xf2, 0xf1, 0x0e, 0x29, 0x11, 0x04, 0x8e, 0x00, + 0x00, 0x00, 0xaf, 0xec, 0x11, 0xdf, 0xe2, 0xd3, + 0xe1, 0xec, 0x05, 0xbe, 0x10, 0xee, 0x03, 0xbe, + 0x0a, 0xf2, 0xf1, 0x0e, 0x29, 0x11, 0x04, 0x49, + 0x00, 0x00, 0x00, 0xaf, 0xec, 0x26, 0xd3, 0xeb, + 0x5f, 0x04, 0x00, 0xa9, 0xec, 0x15, 0xd3, 0x43, + 0x90, 0x01, 0x00, 0x00, 0xb6, 0x5f, 0x04, 0x00, + 0x24, 0x02, 0x00, 0x04, 0x14, 0x02, 0x00, 0x00, + 0x9e, 0xd7, 0xdf, 0x5f, 0x05, 0x00, 0xd3, 0xf1, + 0xf1, 0x0e, 0x29, 0x11, 0x04, 0x4b, 0x00, 0x00, + 0x00, 0xaf, 0xec, 0x0a, 0xdf, 0x5f, 0x06, 0x00, + 0xd3, 0xf1, 0xf1, 0x0e, 0x29, 0x11, 0x04, 0x4a, + 0x00, 0x00, 0x00, 0xaf, 0xed, 0x0d, 0x11, 0x04, + 0x1b, 0x00, 0x00, 0x00, 0xaf, 0x6a, 0x35, 0x05, + 0x00, 0x00, 0xd3, 0xf5, 0xec, 0x06, 0xdf, 0xd3, + 0xf1, 0x0e, 0x29, 0x5f, 0x07, 0x00, 0x43, 0xb6, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xcf, + 0xb6, 0xaa, 0xec, 0x18, 0xdf, 0x04, 0x15, 0x02, + 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, 0xc7, + 0x04, 0xba, 0x01, 0x00, 0x00, 0x24, 0x02, 0x00, + 0xf1, 0x0e, 0x29, 0x5f, 0x08, 0x00, 0x43, 0xb6, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xcf, + 0xb6, 0xaa, 0xec, 0x2c, 0xdf, 0x04, 0x15, 0x02, + 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, 0x5f, + 0x07, 0x00, 0xeb, 0x04, 0xba, 0x01, 0x00, 0x00, + 0x24, 0x02, 0x00, 0xf1, 0x0e, 0x5f, 0x07, 0x00, + 0x43, 0xa3, 0x01, 0x00, 0x00, 0x5f, 0x08, 0x00, + 0xc7, 0x48, 0x24, 0x01, 0x00, 0x0e, 0x29, 0x5f, + 0x09, 0x00, 0xeb, 0xc4, 0x0c, 0x5f, 0x0a, 0x00, + 0xd3, 0xf1, 0xc4, 0x0d, 0x5f, 0x08, 0x00, 0x43, + 0xa3, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0x0e, 0xd3, 0x5f, 0x0b, 0x00, 0xab, 0xec, 0x28, + 0xdf, 0x04, 0x16, 0x02, 0x00, 0x00, 0x43, 0x5d, + 0x00, 0x00, 0x00, 0x5f, 0x0c, 0x00, 0x43, 0x01, + 0x02, 0x00, 0x00, 0xd3, 0x43, 0x17, 0x02, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x24, 0x01, 0x00, 0x24, + 0x01, 0x00, 0xf1, 0x0e, 0xef, 0xad, 0x01, 0xd3, + 0x5f, 0x0d, 0x00, 0xab, 0xec, 0x10, 0xdf, 0xd3, + 0x43, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xf1, 0x0e, 0xef, 0x97, 0x01, 0xd3, 0x5f, 0x0e, + 0x00, 0xab, 0x11, 0xed, 0x10, 0x0e, 0xd3, 0x5f, + 0x0f, 0x00, 0xab, 0x11, 0xed, 0x07, 0x0e, 0xd3, + 0x5f, 0x10, 0x00, 0xab, 0xec, 0x21, 0xdf, 0x04, + 0xde, 0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, + 0x00, 0xc3, 0x0d, 0x04, 0x18, 0x02, 0x00, 0x00, + 0xd3, 0x04, 0xba, 0x01, 0x00, 0x00, 0x24, 0x04, + 0x00, 0xf1, 0x0e, 0xef, 0x5e, 0x01, 0xd3, 0x5f, + 0x06, 0x00, 0xab, 0xec, 0x2c, 0xdf, 0x04, 0xde, + 0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, + 0xc3, 0x0d, 0x04, 0x18, 0x02, 0x00, 0x00, 0x5f, + 0x05, 0x00, 0xd3, 0xf1, 0x04, 0xba, 0x01, 0x00, + 0x00, 0x24, 0x04, 0x00, 0xf1, 0x0e, 0xd3, 0xeb, + 0xc4, 0x0f, 0xb7, 0xc4, 0x08, 0xef, 0x2c, 0x01, + 0x5f, 0x11, 0x00, 0x43, 0x19, 0x02, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0xec, 0x0f, 0xdf, 0x04, + 0xde, 0x01, 0x00, 0x00, 0xf1, 0x0e, 0xb7, 0xc4, + 0x07, 0xef, 0x10, 0x01, 0xc3, 0x0d, 0x43, 0x7f, + 0x01, 0x00, 0x00, 0x04, 0x95, 0x00, 0x00, 0x00, + 0x24, 0x01, 0x00, 0xec, 0x2d, 0xd3, 0x5f, 0x12, + 0x00, 0x42, 0x45, 0x00, 0x00, 0x00, 0xab, 0xec, + 0x21, 0xdf, 0xc2, 0x43, 0x5d, 0x00, 0x00, 0x00, + 0xc3, 0x0d, 0x04, 0xd0, 0x01, 0x00, 0x00, 0xd3, + 0xeb, 0x04, 0x1a, 0x02, 0x00, 0x00, 0x24, 0x04, + 0x00, 0xf1, 0x0e, 0xb7, 0xc4, 0x07, 0xef, 0xd3, + 0x00, 0xc3, 0x06, 0x04, 0x1b, 0x00, 0x00, 0x00, + 0xaf, 0xec, 0x32, 0xd3, 0x42, 0x37, 0x00, 0x00, + 0x00, 0xec, 0x1f, 0xdf, 0x04, 0x1b, 0x02, 0x00, + 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, 0xd3, 0x42, + 0x37, 0x00, 0x00, 0x00, 0x04, 0xba, 0x01, 0x00, + 0x00, 0x24, 0x02, 0x00, 0xf1, 0x0e, 0xef, 0xa3, + 0x00, 0xdf, 0x04, 0x1c, 0x02, 0x00, 0x00, 0xf1, + 0x0e, 0xef, 0x98, 0x00, 0xd3, 0x42, 0x3d, 0x00, + 0x00, 0x00, 0x11, 0xec, 0x0d, 0x0e, 0xd3, 0x42, + 0x3d, 0x00, 0x00, 0x00, 0x42, 0x37, 0x00, 0x00, + 0x00, 0x11, 0xed, 0x07, 0x0e, 0x04, 0x94, 0x00, + 0x00, 0x00, 0xc4, 0x0e, 0xc3, 0x0d, 0x04, 0x94, + 0x00, 0x00, 0x00, 0xb0, 0xec, 0x1d, 0xdf, 0xc2, + 0x43, 0x5d, 0x00, 0x00, 0x00, 0xc3, 0x0e, 0x04, + 0x1d, 0x02, 0x00, 0x00, 0xc3, 0x0d, 0x04, 0x1e, + 0x02, 0x00, 0x00, 0x24, 0x04, 0x00, 0xf1, 0x0e, + 0xee, 0x4a, 0xd3, 0x42, 0x45, 0x00, 0x00, 0x00, + 0xf5, 0xec, 0x1a, 0xdf, 0x04, 0xde, 0x01, 0x00, + 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, 0xc3, 0x0e, + 0x04, 0x1f, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, + 0xf1, 0x0e, 0xee, 0x28, 0xc3, 0x0e, 0x04, 0x94, + 0x00, 0x00, 0x00, 0xb0, 0xec, 0x16, 0xdf, 0xc2, + 0x43, 0x5d, 0x00, 0x00, 0x00, 0xc3, 0x0e, 0x04, + 0x20, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0xf1, + 0x0e, 0xee, 0x09, 0xdf, 0x04, 0x21, 0x02, 0x00, + 0x00, 0xf1, 0x0e, 0x04, 0x22, 0x02, 0x00, 0x00, + 0xc4, 0x0a, 0x07, 0xc4, 0x04, 0xb6, 0xcb, 0xb6, + 0xcc, 0xb6, 0xce, 0xc3, 0x07, 0x6a, 0xcb, 0x00, + 0x00, 0x00, 0x04, 0xba, 0x01, 0x00, 0x00, 0xc4, + 0x0a, 0xd3, 0xeb, 0xc4, 0x0f, 0xd4, 0x5f, 0x13, + 0x00, 0xa9, 0xec, 0x12, 0xc3, 0x0f, 0xec, 0x0e, + 0xdf, 0x04, 0x14, 0x02, 0x00, 0x00, 0xf1, 0x0e, + 0xdf, 0xc3, 0x0a, 0xf1, 0x29, 0xb6, 0xcd, 0xc9, + 0xc3, 0x0f, 0xa7, 0x6a, 0x89, 0x00, 0x00, 0x00, + 0x94, 0x03, 0xc9, 0xd3, 0xac, 0xec, 0x0e, 0x5f, + 0x14, 0x00, 0xd3, 0xc9, 0x48, 0xd4, 0xb7, 0x9e, + 0xf2, 0x0e, 0xee, 0x43, 0xc9, 0xc4, 0x10, 0xc9, + 0xb7, 0x9e, 0xc3, 0x0f, 0xa7, 0xec, 0x0d, 0xc9, + 0xb7, 0x9e, 0xd3, 0xac, 0x97, 0xec, 0x05, 0x94, + 0x02, 0xee, 0xed, 0xc9, 0xc3, 0x10, 0xa9, 0xec, + 0x1e, 0xdf, 0x04, 0x23, 0x02, 0x00, 0x00, 0x43, + 0x5d, 0x00, 0x00, 0x00, 0xc9, 0xc3, 0x10, 0x9f, + 0xb7, 0x9e, 0x04, 0x24, 0x02, 0x00, 0x00, 0x24, + 0x02, 0x00, 0xf1, 0x0e, 0xee, 0x09, 0xdf, 0x04, + 0x25, 0x02, 0x00, 0x00, 0xf1, 0x0e, 0xca, 0x5f, + 0x15, 0x00, 0xaa, 0xec, 0x24, 0xc3, 0x0f, 0xca, + 0x9f, 0xbb, 0xa9, 0xec, 0x1c, 0xdf, 0x04, 0x26, + 0x02, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, + 0xc3, 0x0f, 0xca, 0x9f, 0x04, 0x27, 0x02, 0x00, + 0x00, 0x24, 0x02, 0x00, 0xf1, 0x0e, 0xee, 0x06, + 0x94, 0x02, 0xef, 0x74, 0xff, 0xb7, 0xc4, 0x08, + 0xc9, 0xc3, 0x0f, 0xb0, 0xec, 0x0c, 0xc3, 0x0f, + 0xbf, 0xe8, 0x03, 0xa9, 0xec, 0x04, 0xb7, 0xc4, + 0x09, 0xc3, 0x09, 0x97, 0xec, 0x24, 0x5f, 0x16, + 0x00, 0xec, 0x0f, 0x5f, 0x17, 0x00, 0x43, 0xc5, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xee, + 0x0d, 0x5f, 0x17, 0x00, 0x43, 0x30, 0x00, 0x00, + 0x00, 0xd3, 0x24, 0x01, 0x00, 0xc5, 0x04, 0xeb, + 0xcb, 0xc3, 0x08, 0xec, 0x1e, 0xc8, 0xc7, 0xa7, + 0xec, 0x19, 0xc3, 0x04, 0xc8, 0x48, 0x8e, 0xd1, + 0xc9, 0xb6, 0xa2, 0xb0, 0x11, 0xed, 0x06, 0x0e, + 0xc9, 0xc3, 0x0f, 0xaa, 0xed, 0x05, 0x94, 0x01, + 0xee, 0xe4, 0xc8, 0xc7, 0xa7, 0x6a, 0x5a, 0x01, + 0x00, 0x00, 0xc3, 0x0a, 0x97, 0xec, 0x12, 0x5f, + 0x18, 0x00, 0x04, 0x20, 0x02, 0x00, 0x00, 0xf1, + 0x0e, 0x04, 0x22, 0x02, 0x00, 0x00, 0xc4, 0x0a, + 0xd4, 0x5f, 0x13, 0x00, 0xa9, 0xec, 0x13, 0xc8, + 0xc7, 0xa7, 0xec, 0x0e, 0xdf, 0x04, 0x14, 0x02, + 0x00, 0x00, 0xf1, 0x0e, 0xdf, 0xc3, 0x0a, 0xf1, + 0x29, 0xc8, 0xcd, 0xc9, 0xc7, 0xa7, 0x6a, 0x21, + 0x01, 0x00, 0x00, 0xc3, 0x04, 0xc9, 0x48, 0xc4, + 0x05, 0x5f, 0x17, 0x00, 0x43, 0x67, 0x00, 0x00, + 0x00, 0xd3, 0xc3, 0x05, 0x24, 0x02, 0x00, 0xc5, + 0x11, 0x97, 0x6b, 0x00, 0x01, 0x00, 0x00, 0xc3, + 0x11, 0x42, 0x40, 0x00, 0x00, 0x00, 0x97, 0xec, + 0x1e, 0xdf, 0x04, 0xde, 0x01, 0x00, 0x00, 0x43, + 0x5d, 0x00, 0x00, 0x00, 0x5f, 0x06, 0x00, 0xc3, + 0x05, 0xf1, 0x04, 0xba, 0x01, 0x00, 0x00, 0x24, + 0x02, 0x00, 0xf1, 0x0e, 0xee, 0x2e, 0xc3, 0x05, + 0x8e, 0xc3, 0x05, 0xb6, 0xa2, 0xaf, 0x11, 0xed, + 0x11, 0x0e, 0xc3, 0x05, 0x43, 0xbc, 0x01, 0x00, + 0x00, 0xc0, 0x00, 0xc0, 0x01, 0x34, 0x24, 0x01, + 0x00, 0xec, 0x08, 0xdf, 0xc3, 0x05, 0xf1, 0x0e, + 0xee, 0x0a, 0xdf, 0x5f, 0x05, 0x00, 0xc3, 0x05, + 0xf1, 0xf1, 0x0e, 0xdf, 0x04, 0x28, 0x02, 0x00, + 0x00, 0xf1, 0x0e, 0x04, 0x41, 0x00, 0x00, 0x00, + 0xc3, 0x11, 0xac, 0xec, 0x12, 0x5f, 0x14, 0x00, + 0xc3, 0x11, 0x42, 0x41, 0x00, 0x00, 0x00, 0xd4, + 0xb7, 0x9e, 0xf2, 0x0e, 0xee, 0x5c, 0x26, 0x00, + 0x00, 0xc4, 0x12, 0xc3, 0x11, 0x42, 0x42, 0x00, + 0x00, 0x00, 0xec, 0x11, 0xc3, 0x12, 0x43, 0xa3, + 0x01, 0x00, 0x00, 0x04, 0x29, 0x02, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xc3, 0x11, 0x42, 0x43, + 0x00, 0x00, 0x00, 0xec, 0x11, 0xc3, 0x12, 0x43, + 0xa3, 0x01, 0x00, 0x00, 0x04, 0x2a, 0x02, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0xdf, 0x04, 0xde, + 0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, + 0xc3, 0x12, 0x43, 0x5c, 0x00, 0x00, 0x00, 0x04, + 0xbb, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x04, + 0xba, 0x01, 0x00, 0x00, 0x24, 0x02, 0x00, 0xf1, + 0x0e, 0x94, 0x03, 0xca, 0x5f, 0x19, 0x00, 0xa9, + 0xec, 0x22, 0xc7, 0xca, 0x9f, 0xbb, 0xa9, 0xec, + 0x1b, 0xdf, 0x04, 0x26, 0x02, 0x00, 0x00, 0x43, + 0x5d, 0x00, 0x00, 0x00, 0xc7, 0xca, 0x9f, 0x04, + 0x2b, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0xf1, + 0x0e, 0xee, 0x06, 0x94, 0x02, 0xef, 0xdd, 0xfe, + 0xc3, 0x0a, 0xec, 0x06, 0xdf, 0xc3, 0x0a, 0xf1, + 0x0e, 0x5f, 0x08, 0x00, 0x43, 0x2c, 0x02, 0x00, + 0x00, 0xd3, 0x24, 0x01, 0x00, 0x0e, 0x5f, 0x07, + 0x00, 0x43, 0xb6, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0xd1, 0xb6, 0xa9, 0xec, 0x35, 0x5f, + 0x09, 0x00, 0xc3, 0x0c, 0x1b, 0x11, 0xb1, 0xed, + 0x04, 0x1b, 0x72, 0x1b, 0x1b, 0x04, 0x2d, 0x02, + 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, 0xc9, + 0x04, 0x2e, 0x02, 0x00, 0x00, 0x5f, 0x09, 0x00, + 0xc3, 0x0c, 0x48, 0x24, 0x03, 0x00, 0x1b, 0x72, + 0x1b, 0x4a, 0x29, 0xdf, 0x5f, 0x06, 0x00, 0xd3, + 0xf1, 0xf1, 0x0e, 0x29, 0x0c, 0x43, 0x02, 0x01, + 0xee, 0x07, 0x02, 0x01, 0x02, 0x03, 0x05, 0x00, + 0x3d, 0x03, 0xd8, 0x06, 0x00, 0x01, 0x00, 0x9a, + 0x06, 0x00, 0x01, 0x00, 0xde, 0x08, 0x00, 0x00, + 0x00, 0xd0, 0x07, 0x03, 0x03, 0xe2, 0x07, 0x0a, + 0x01, 0xe0, 0x07, 0x09, 0x01, 0xe0, 0x03, 0x0e, + 0x00, 0xe4, 0x03, 0x0f, 0x00, 0xdf, 0xec, 0x30, + 0xe0, 0xd4, 0xb0, 0xec, 0x13, 0xe1, 0x43, 0xa3, + 0x01, 0x00, 0x00, 0xe2, 0x42, 0x8f, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0xd4, 0xe4, 0xd4, + 0xec, 0x16, 0xe2, 0x5f, 0x04, 0x00, 0xd4, 0x48, + 0x48, 0xcf, 0xec, 0x0c, 0xe1, 0x43, 0xa3, 0x01, + 0x00, 0x00, 0xc7, 0x24, 0x01, 0x00, 0x0e, 0xe1, + 0x43, 0xa3, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, + 0x00, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xf0, 0x07, + 0x01, 0x00, 0x01, 0x03, 0x01, 0x02, 0x2c, 0x01, + 0xd8, 0x06, 0x00, 0x01, 0x00, 0xee, 0x07, 0x10, + 0x01, 0x07, 0x02, 0x30, 0x07, 0x02, 0x39, 0xd3, + 0xb6, 0x48, 0xc0, 0x00, 0xaa, 0xec, 0x14, 0xd3, + 0xb6, 0x48, 0xc0, 0x01, 0xa8, 0xec, 0x0c, 0xdf, + 0xd3, 0x04, 0x47, 0x00, 0x00, 0x00, 0xf2, 0x0e, + 0xee, 0x0a, 0xdf, 0xd3, 0x04, 0x30, 0x02, 0x00, + 0x00, 0xf2, 0x0e, 0xdf, 0x04, 0x18, 0x02, 0x00, + 0x00, 0xf1, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xf2, + 0x07, 0x01, 0x04, 0x01, 0x05, 0x03, 0x14, 0xa1, + 0x04, 0x05, 0xd8, 0x06, 0x00, 0x01, 0x00, 0x9a, + 0x06, 0x00, 0x00, 0x00, 0xe2, 0x08, 0x00, 0x01, + 0x00, 0x82, 0x06, 0x00, 0x02, 0x00, 0x9e, 0x07, + 0x00, 0x03, 0x00, 0xd0, 0x07, 0x03, 0x03, 0xee, + 0x07, 0x10, 0x01, 0xf4, 0x07, 0x13, 0x01, 0x07, + 0x20, 0x5e, 0x22, 0x28, 0x5b, 0x5e, 0x5c, 0x5c, + 0x22, 0x5d, 0x7c, 0x5c, 0x5c, 0x2e, 0x29, 0x2a, + 0x22, 0x07, 0x98, 0x01, 0x00, 0x00, 0x02, 0x01, + 0x44, 0x00, 0x00, 0x00, 0x09, 0x06, 0x00, 0x00, + 0x00, 0x05, 0x08, 0xf5, 0xff, 0xff, 0xff, 0x0c, + 0x00, 0x06, 0x01, 0x22, 0x0e, 0x01, 0x01, 0x0a, + 0x27, 0x00, 0x00, 0x00, 0x1a, 0x0c, 0x01, 0x0a, + 0x14, 0x00, 0x00, 0x00, 0x16, 0x03, 0x00, 0x00, + 0x00, 0x21, 0x00, 0x23, 0x00, 0x5b, 0x00, 0x5d, + 0x00, 0xff, 0xff, 0x08, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x5c, 0x04, 0x0d, 0x01, 0x1b, 0x08, 0xd4, + 0xff, 0xff, 0xff, 0x01, 0x22, 0x0d, 0x00, 0x0b, + 0x07, 0x20, 0x5e, 0x27, 0x28, 0x5b, 0x5e, 0x5c, + 0x5c, 0x27, 0x5d, 0x7c, 0x5c, 0x5c, 0x2e, 0x29, + 0x2a, 0x27, 0x07, 0x98, 0x01, 0x00, 0x00, 0x02, + 0x01, 0x44, 0x00, 0x00, 0x00, 0x09, 0x06, 0x00, + 0x00, 0x00, 0x05, 0x08, 0xf5, 0xff, 0xff, 0xff, + 0x0c, 0x00, 0x06, 0x01, 0x27, 0x0e, 0x01, 0x01, + 0x0a, 0x27, 0x00, 0x00, 0x00, 0x1a, 0x0c, 0x01, + 0x0a, 0x14, 0x00, 0x00, 0x00, 0x16, 0x03, 0x00, + 0x00, 0x00, 0x26, 0x00, 0x28, 0x00, 0x5b, 0x00, + 0x5d, 0x00, 0xff, 0xff, 0x08, 0x03, 0x00, 0x00, + 0x00, 0x01, 0x5c, 0x04, 0x0d, 0x01, 0x1b, 0x08, + 0xd4, 0xff, 0xff, 0xff, 0x01, 0x27, 0x0d, 0x00, + 0x0b, 0x07, 0x16, 0x5e, 0x5c, 0x3c, 0x5b, 0x5e, + 0x5c, 0x3e, 0x5d, 0x2b, 0x5c, 0x3e, 0x07, 0x74, + 0x00, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00, + 0x09, 0x06, 0x00, 0x00, 0x00, 0x05, 0x08, 0xf5, + 0xff, 0xff, 0xff, 0x0c, 0x00, 0x06, 0x01, 0x3c, + 0x1d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x00, + 0x00, 0x16, 0x02, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x3f, 0x00, 0xff, 0xff, 0x0b, 0x01, 0x3e, 0x0d, + 0x00, 0x0b, 0x07, 0x16, 0x5e, 0x5c, 0x5b, 0x5b, + 0x5e, 0x5c, 0x5d, 0x5d, 0x2b, 0x5c, 0x5d, 0x07, + 0x74, 0x00, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, + 0x00, 0x09, 0x06, 0x00, 0x00, 0x00, 0x05, 0x08, + 0xf5, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x06, 0x01, + 0x5b, 0x1d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, + 0x00, 0x00, 0x16, 0x02, 0x00, 0x00, 0x00, 0x5c, + 0x00, 0x5e, 0x00, 0xff, 0xff, 0x0b, 0x01, 0x5d, + 0x0d, 0x00, 0x0b, 0x07, 0x02, 0x30, 0x07, 0x02, + 0x31, 0x07, 0x02, 0x32, 0x07, 0x02, 0x33, 0x07, + 0x02, 0x34, 0x07, 0x02, 0x35, 0x07, 0x02, 0x36, + 0x07, 0x02, 0x37, 0x07, 0x02, 0x38, 0x07, 0x02, + 0x39, 0x07, 0x56, 0x5e, 0x5b, 0x30, 0x2d, 0x39, + 0x61, 0x2d, 0x7a, 0x5f, 0x5d, 0x2b, 0x5b, 0x2e, + 0x5d, 0x3f, 0x5b, 0x30, 0x2d, 0x39, 0x61, 0x2d, + 0x7a, 0x5f, 0x5d, 0x2a, 0x5b, 0x65, 0x45, 0x70, + 0x50, 0x5d, 0x3f, 0x5b, 0x2b, 0x2d, 0x5d, 0x3f, + 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2a, 0x07, 0x9e, + 0x03, 0x00, 0x00, 0x01, 0x00, 0xc7, 0x00, 0x00, + 0x00, 0x09, 0x06, 0x00, 0x00, 0x00, 0x05, 0x08, + 0xf5, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x06, 0x1d, + 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x00, 0x00, + 0x16, 0x03, 0x00, 0x30, 0x00, 0x39, 0x00, 0x5f, + 0x00, 0x5f, 0x00, 0x61, 0x00, 0x7a, 0x00, 0x0b, + 0x1d, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x16, 0x01, 0x00, 0x2e, 0x00, 0x2e, 0x00, + 0x0b, 0x1d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, + 0x00, 0x00, 0x16, 0x03, 0x00, 0x30, 0x00, 0x39, + 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x61, 0x00, 0x7a, + 0x00, 0x0b, 0x1d, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x16, 0x04, 0x00, 0x45, 0x00, + 0x45, 0x00, 0x50, 0x00, 0x50, 0x00, 0x65, 0x00, + 0x65, 0x00, 0x70, 0x00, 0x70, 0x00, 0x0b, 0x1d, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x16, 0x02, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2d, + 0x00, 0x2d, 0x00, 0x0b, 0x1d, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x7f, 0x01, 0x00, 0x00, 0x00, 0x16, 0x01, 0x00, + 0x30, 0x00, 0x39, 0x00, 0x0b, 0x0d, 0x00, 0x0b, + 0xdf, 0x97, 0xec, 0x05, 0xe0, 0xd3, 0xf1, 0x29, + 0xd3, 0xeb, 0xb6, 0xa9, 0x6a, 0x13, 0x02, 0x00, + 0x00, 0x04, 0x8f, 0x01, 0x00, 0x00, 0xcb, 0xd3, + 0xcc, 0xb6, 0xcd, 0x07, 0xce, 0xd3, 0xb6, 0x48, + 0x11, 0x04, 0xb8, 0x01, 0x00, 0x00, 0xaf, 0xec, + 0x19, 0x04, 0x49, 0x00, 0x00, 0x00, 0xcb, 0xd3, + 0x43, 0xbc, 0x01, 0x00, 0x00, 0xc0, 0x00, 0xc0, + 0x01, 0x34, 0x24, 0x01, 0x00, 0xce, 0xef, 0xb3, + 0x01, 0x11, 0x04, 0xb7, 0x01, 0x00, 0x00, 0xaf, + 0xec, 0x19, 0x04, 0x49, 0x00, 0x00, 0x00, 0xcb, + 0xd3, 0x43, 0xbc, 0x01, 0x00, 0x00, 0xc0, 0x02, + 0xc0, 0x03, 0x34, 0x24, 0x01, 0x00, 0xce, 0xef, + 0x92, 0x01, 0x11, 0x04, 0xbb, 0x01, 0x00, 0x00, + 0xaf, 0xec, 0x0a, 0x04, 0x32, 0x02, 0x00, 0x00, + 0xcb, 0xef, 0x80, 0x01, 0x11, 0x04, 0x23, 0x02, + 0x00, 0x00, 0xaf, 0xec, 0x1e, 0xd3, 0x43, 0xbc, + 0x01, 0x00, 0x00, 0xc0, 0x04, 0xc0, 0x05, 0x34, + 0x24, 0x01, 0x00, 0xd2, 0x6a, 0x65, 0x01, 0x00, + 0x00, 0x04, 0x33, 0x02, 0x00, 0x00, 0xcb, 0xef, + 0x5a, 0x01, 0x11, 0x04, 0xde, 0x01, 0x00, 0x00, + 0xaf, 0xec, 0x1b, 0xd3, 0x43, 0xbc, 0x01, 0x00, + 0x00, 0xc0, 0x06, 0xc0, 0x07, 0x34, 0x24, 0x01, + 0x00, 0xd2, 0xec, 0x2e, 0x04, 0x33, 0x02, 0x00, + 0x00, 0xcb, 0xef, 0x37, 0x01, 0x11, 0x04, 0xba, + 0x01, 0x00, 0x00, 0xaf, 0xed, 0x1c, 0x11, 0x04, + 0x22, 0x02, 0x00, 0x00, 0xaf, 0xed, 0x13, 0x11, + 0x04, 0x34, 0x02, 0x00, 0x00, 0xaf, 0xed, 0x0a, + 0x11, 0x04, 0xd9, 0x01, 0x00, 0x00, 0xaf, 0xec, + 0x0c, 0x04, 0x35, 0x02, 0x00, 0x00, 0xcb, 0xb7, + 0xcd, 0xef, 0x08, 0x01, 0x11, 0x04, 0xaf, 0x01, + 0x00, 0x00, 0xaf, 0xec, 0x0a, 0x04, 0x33, 0x02, + 0x00, 0x00, 0xcb, 0xef, 0xf6, 0x00, 0x11, 0xc0, + 0x08, 0xaf, 0xed, 0x37, 0x11, 0xc0, 0x09, 0xaf, + 0xed, 0x31, 0x11, 0xc0, 0x0a, 0xaf, 0xed, 0x2b, + 0x11, 0xc0, 0x0b, 0xaf, 0xed, 0x25, 0x11, 0xc0, + 0x0c, 0xaf, 0xed, 0x1f, 0x11, 0xc0, 0x0d, 0xaf, + 0xed, 0x19, 0x11, 0xc0, 0x0e, 0xaf, 0xed, 0x13, + 0x11, 0xc0, 0x0f, 0xaf, 0xed, 0x0d, 0x11, 0xc0, + 0x10, 0xaf, 0xed, 0x07, 0x11, 0xc0, 0x11, 0xaf, + 0xec, 0x19, 0x04, 0x47, 0x00, 0x00, 0x00, 0xcb, + 0xd3, 0x43, 0xbc, 0x01, 0x00, 0x00, 0xc0, 0x12, + 0xc0, 0x13, 0x34, 0x24, 0x01, 0x00, 0xce, 0xef, + 0xa2, 0x00, 0x11, 0x04, 0xe4, 0x01, 0x00, 0x00, + 0xaf, 0xec, 0x06, 0xb7, 0xcd, 0xef, 0x94, 0x00, + 0xe1, 0xd3, 0xf1, 0xec, 0x06, 0xd3, 0xeb, 0xb7, + 0x9f, 0xcd, 0xd3, 0x43, 0xc4, 0x01, 0x00, 0x00, + 0x04, 0x9e, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, + 0xec, 0x09, 0x04, 0x36, 0x02, 0x00, 0x00, 0xcb, + 0xee, 0x71, 0xd3, 0x43, 0xc4, 0x01, 0x00, 0x00, + 0x04, 0x9a, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, + 0xec, 0x09, 0x04, 0x4b, 0x00, 0x00, 0x00, 0xcb, + 0xee, 0x59, 0xd3, 0x04, 0xed, 0x00, 0x00, 0x00, + 0xaf, 0x11, 0xed, 0x09, 0x0e, 0xd3, 0x04, 0x37, + 0x02, 0x00, 0x00, 0xaf, 0xec, 0x09, 0x04, 0x38, + 0x02, 0x00, 0x00, 0xcb, 0xee, 0x3d, 0xd3, 0x04, + 0x03, 0x00, 0x00, 0x00, 0xaf, 0x11, 0xed, 0x09, + 0x0e, 0xd3, 0x04, 0x02, 0x00, 0x00, 0x00, 0xaf, + 0xec, 0x09, 0x04, 0x48, 0x00, 0x00, 0x00, 0xcb, + 0xee, 0x21, 0xd3, 0x04, 0x01, 0x00, 0x00, 0x00, + 0xaf, 0xec, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00, + 0xcb, 0xee, 0x10, 0xd3, 0x04, 0x46, 0x00, 0x00, + 0x00, 0xaf, 0xec, 0x07, 0x04, 0x46, 0x00, 0x00, + 0x00, 0xcb, 0x0e, 0xca, 0xec, 0x06, 0xca, 0xb6, + 0x48, 0xeb, 0xcd, 0xc9, 0xb6, 0xa9, 0xec, 0x0d, + 0xd3, 0x43, 0xb0, 0x01, 0x00, 0x00, 0xb6, 0xc9, + 0x24, 0x02, 0x00, 0xcc, 0xe0, 0xc8, 0xc7, 0xf2, + 0x0e, 0xd3, 0x43, 0xb0, 0x01, 0x00, 0x00, 0xc8, + 0xeb, 0x24, 0x01, 0x00, 0xd7, 0xef, 0xea, 0xfd, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xf4, 0x07, 0x01, + 0x01, 0x01, 0x03, 0x00, 0x00, 0x19, 0x02, 0xd8, + 0x06, 0x00, 0x01, 0x00, 0xee, 0x05, 0x00, 0x00, + 0x00, 0xd3, 0xd3, 0xeb, 0xb7, 0x9f, 0x48, 0xcf, + 0x04, 0xde, 0x01, 0x00, 0x00, 0xaf, 0x11, 0xed, + 0x09, 0x0e, 0xc7, 0x04, 0x21, 0x02, 0x00, 0x00, + 0xaf, 0x28, 0x0c, 0x43, 0x02, 0x01, 0xf6, 0x07, + 0x01, 0x04, 0x01, 0x08, 0x03, 0x00, 0x7c, 0x05, + 0xe8, 0x05, 0x00, 0x01, 0x00, 0xf2, 0x08, 0x00, + 0x00, 0x00, 0xf4, 0x08, 0x00, 0x01, 0x00, 0xf6, + 0x08, 0x00, 0x02, 0x00, 0xd8, 0x06, 0x00, 0x03, + 0x00, 0xde, 0x07, 0x08, 0x01, 0xf4, 0x07, 0x13, + 0x01, 0xf6, 0x07, 0x14, 0x01, 0xdf, 0xd3, 0x48, + 0xeb, 0xcb, 0xdf, 0xd3, 0xb7, 0x9e, 0x48, 0x04, + 0x28, 0x02, 0x00, 0x00, 0xaf, 0xec, 0x0e, 0xd3, + 0xb8, 0x9e, 0xd7, 0xc7, 0xb8, 0xdf, 0xd3, 0x48, + 0xeb, 0x9e, 0x9e, 0xcb, 0xc7, 0xcc, 0xe0, 0xdf, + 0xd3, 0x48, 0xf1, 0xec, 0x4f, 0xb7, 0xcd, 0xd3, + 0x90, 0xdb, 0xdf, 0xeb, 0xa7, 0xec, 0x45, 0xc9, + 0x95, 0x01, 0xdf, 0xd3, 0x48, 0xd2, 0x04, 0xba, + 0x01, 0x00, 0x00, 0xaf, 0x11, 0xed, 0x09, 0x0e, + 0xca, 0x04, 0x22, 0x02, 0x00, 0x00, 0xaf, 0xed, + 0x2b, 0xee, 0x1c, 0x11, 0x7f, 0x7b, 0x74, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x02, 0x0e, 0x3e, + 0x7a, 0x39, 0x02, 0x00, 0x00, 0x00, 0x00, 0x82, + 0x02, 0x0e, 0x3e, 0x85, 0xee, 0x06, 0xe1, 0xd3, + 0xf1, 0xee, 0xe1, 0x0e, 0xc7, 0x95, 0x01, 0xb8, + 0xcd, 0xee, 0xb5, 0xd3, 0xc8, 0x26, 0x02, 0x00, + 0x28, 0x0c, 0x43, 0x02, 0x01, 0xf8, 0x07, 0x02, + 0x02, 0x02, 0x03, 0x05, 0x00, 0x67, 0x04, 0xe8, + 0x05, 0x00, 0x01, 0x00, 0xf8, 0x08, 0x00, 0x01, + 0x00, 0x9c, 0x08, 0x00, 0x00, 0x00, 0xd8, 0x06, + 0x00, 0x01, 0x00, 0xde, 0x07, 0x08, 0x01, 0xee, + 0x07, 0x10, 0x01, 0xf0, 0x07, 0x11, 0x01, 0xf2, + 0x07, 0x12, 0x01, 0xf4, 0x07, 0x13, 0x01, 0xc2, + 0xcb, 0xd3, 0xd4, 0xa8, 0xec, 0x60, 0xdf, 0xd3, + 0x92, 0xd7, 0x48, 0xd0, 0x04, 0xba, 0x01, 0x00, + 0x00, 0xaf, 0x11, 0xed, 0x09, 0x0e, 0xc8, 0x04, + 0x22, 0x02, 0x00, 0x00, 0xaf, 0xec, 0x11, 0xc7, + 0xeb, 0xb7, 0xa9, 0xec, 0x27, 0xe0, 0x04, 0xd9, + 0x01, 0x00, 0x00, 0xf1, 0x0e, 0xee, 0x1d, 0xe0, + 0xc7, 0xf1, 0x0e, 0xdf, 0xd3, 0x48, 0x04, 0x28, + 0x02, 0x00, 0x00, 0xaf, 0xec, 0x0e, 0xe1, 0xc8, + 0xf1, 0x0e, 0xd3, 0x90, 0xd7, 0xdf, 0xd3, 0x92, + 0xd7, 0x48, 0xcc, 0xe2, 0xc8, 0xf1, 0x0e, 0x5f, + 0x04, 0x00, 0xc8, 0xf1, 0xec, 0x08, 0x04, 0xd9, + 0x01, 0x00, 0x00, 0xee, 0x06, 0x04, 0x3d, 0x02, + 0x00, 0x00, 0xcb, 0xee, 0x9d, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0xfa, 0x07, 0x02, 0x00, 0x02, 0x04, + 0x01, 0x00, 0x1a, 0x02, 0xd8, 0x06, 0x00, 0x01, + 0x00, 0xac, 0x07, 0x00, 0x01, 0x00, 0xee, 0x07, + 0x10, 0x01, 0xd4, 0xb6, 0xa9, 0xec, 0x12, 0xd3, + 0x04, 0xd9, 0x01, 0x00, 0x00, 0x43, 0x3e, 0x02, + 0x00, 0x00, 0xd4, 0x24, 0x01, 0x00, 0x9e, 0xd7, + 0xdf, 0xd3, 0xf1, 0x29, 0x0c, 0x43, 0x02, 0x01, + 0xfc, 0x07, 0x02, 0x0c, 0x02, 0x08, 0x0b, 0x00, + 0x8f, 0x05, 0x0e, 0xfe, 0x08, 0x00, 0x01, 0x00, + 0xf6, 0x01, 0x00, 0x01, 0x00, 0x80, 0x09, 0x00, + 0x00, 0x00, 0xf8, 0x08, 0x00, 0x01, 0x00, 0xf4, + 0x08, 0x00, 0x02, 0x00, 0x9c, 0x08, 0x00, 0x03, + 0x00, 0x82, 0x09, 0x00, 0x04, 0x00, 0xe8, 0x05, + 0x00, 0x05, 0x00, 0xf2, 0x08, 0x00, 0x06, 0x00, + 0x8e, 0x08, 0x00, 0x07, 0x00, 0x96, 0x07, 0x00, + 0x08, 0x00, 0x84, 0x09, 0x00, 0x09, 0x00, 0xd6, + 0x05, 0x00, 0x0a, 0x00, 0x86, 0x09, 0x00, 0x0b, + 0x00, 0xd4, 0x07, 0x02, 0x01, 0xf6, 0x07, 0x14, + 0x01, 0xf8, 0x07, 0x15, 0x01, 0xde, 0x07, 0x08, + 0x01, 0xf0, 0x07, 0x11, 0x01, 0xf2, 0x07, 0x12, + 0x01, 0xf4, 0x07, 0x13, 0x01, 0xb8, 0x02, 0x10, + 0x00, 0xee, 0x07, 0x10, 0x01, 0xfa, 0x07, 0x16, + 0x01, 0xfc, 0x07, 0x17, 0x01, 0xdf, 0xd3, 0x9f, + 0xb8, 0x9f, 0xcb, 0x06, 0x11, 0xf4, 0xed, 0x0d, + 0x7f, 0x82, 0x00, 0x0e, 0xcc, 0x82, 0x00, 0x0e, + 0xcd, 0x85, 0xee, 0x07, 0x0e, 0xe0, 0xd4, 0xf1, + 0xee, 0xef, 0xc9, 0xc7, 0xa8, 0xec, 0x0c, 0xe1, + 0xd4, 0xc8, 0xf2, 0x0e, 0xc8, 0xc9, 0x26, 0x02, + 0x00, 0x28, 0xe2, 0xd4, 0xb7, 0x9e, 0x48, 0x04, + 0x28, 0x02, 0x00, 0x00, 0xaf, 0xec, 0x0d, 0x5f, + 0x04, 0x00, 0xe2, 0xd4, 0x48, 0xf1, 0x0e, 0xd4, + 0xb8, 0x9e, 0xd8, 0x5f, 0x05, 0x00, 0xe2, 0xd4, + 0x48, 0xf1, 0x0e, 0x5f, 0x06, 0x00, 0xe2, 0xd4, + 0x48, 0xf1, 0x97, 0xec, 0x07, 0xd4, 0xc9, 0x26, + 0x02, 0x00, 0x28, 0xd3, 0xb8, 0x9e, 0xd7, 0xc7, + 0xb8, 0x9f, 0xcb, 0xc2, 0xce, 0xd4, 0xb7, 0x9e, + 0xc4, 0x04, 0xe2, 0xd4, 0x48, 0x43, 0x44, 0x02, + 0x00, 0x00, 0x04, 0xde, 0x01, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x6a, 0xa9, 0x01, 0x00, 0x00, 0xb6, + 0xc4, 0x07, 0x26, 0x00, 0x00, 0xc4, 0x0a, 0xc3, + 0x04, 0xc4, 0x05, 0xc3, 0x05, 0xc8, 0xa7, 0xec, + 0x5d, 0xe2, 0xc3, 0x05, 0x48, 0xb6, 0x48, 0x04, + 0xaf, 0x01, 0x00, 0x00, 0xaf, 0x11, 0xed, 0x0e, + 0x0e, 0xe2, 0xc3, 0x05, 0xb7, 0x9e, 0x48, 0x04, + 0x28, 0x02, 0x00, 0x00, 0xaf, 0xed, 0x3f, 0xee, + 0x1c, 0x11, 0x7f, 0x7a, 0x74, 0x01, 0x00, 0x00, + 0x05, 0x00, 0x82, 0x02, 0x0e, 0x3e, 0x7a, 0x39, + 0x02, 0x00, 0x00, 0x06, 0x00, 0x82, 0x02, 0x0e, + 0x3e, 0x85, 0xee, 0x07, 0xe0, 0xc3, 0x05, 0xf1, + 0xee, 0xe0, 0x0e, 0xc3, 0x0a, 0xc3, 0x07, 0x92, + 0xc4, 0x07, 0x1b, 0x11, 0xb1, 0xed, 0x04, 0x1b, + 0x72, 0x1b, 0x1b, 0xc3, 0x06, 0x1b, 0x72, 0x1b, + 0x4a, 0x94, 0x05, 0xee, 0x9f, 0x5f, 0x07, 0x00, + 0x43, 0x96, 0x01, 0x00, 0x00, 0xc7, 0xb9, 0x9c, + 0xc3, 0x0a, 0xeb, 0xbe, 0x10, 0x24, 0x03, 0x00, + 0xc4, 0x09, 0xc3, 0x09, 0xb7, 0xa9, 0xec, 0x73, + 0x26, 0x00, 0x00, 0xc4, 0x0b, 0xb6, 0xc4, 0x08, + 0xb6, 0xc4, 0x07, 0xc3, 0x07, 0xc3, 0x0a, 0xeb, + 0xa7, 0xec, 0x3b, 0xc3, 0x0b, 0xc3, 0x08, 0x1b, + 0x11, 0xb1, 0xed, 0x04, 0x1b, 0x72, 0x1b, 0x1b, + 0x5f, 0x07, 0x00, 0x43, 0xd2, 0x01, 0x00, 0x00, + 0xc3, 0x0b, 0xc3, 0x08, 0x48, 0x11, 0xed, 0x03, + 0x0e, 0xb6, 0xc3, 0x0a, 0xc3, 0x07, 0x48, 0xb8, + 0x9e, 0x24, 0x02, 0x00, 0x1b, 0x72, 0x1b, 0x4a, + 0xc3, 0x08, 0xb7, 0x9e, 0xc3, 0x09, 0x9d, 0xc4, + 0x08, 0x94, 0x07, 0xee, 0xbf, 0xb6, 0xc4, 0x06, + 0xb6, 0xc4, 0x08, 0xc3, 0x08, 0xc3, 0x09, 0xa7, + 0xec, 0x0f, 0xc3, 0x06, 0xc3, 0x0b, 0xc3, 0x08, + 0x48, 0x9e, 0xc4, 0x06, 0x94, 0x08, 0xee, 0xec, + 0xc3, 0x06, 0xc7, 0xa8, 0xed, 0x05, 0x93, 0x09, + 0xee, 0x89, 0xc3, 0x09, 0xb7, 0xa9, 0x6a, 0xa5, + 0x00, 0x00, 0x00, 0xb6, 0xc4, 0x06, 0xc3, 0x09, + 0xb7, 0x9f, 0xc4, 0x08, 0xc3, 0x04, 0xc4, 0x05, + 0xc3, 0x05, 0xc8, 0xa7, 0x6a, 0x8b, 0x00, 0x00, + 0x00, 0xe2, 0xc3, 0x05, 0x48, 0xb6, 0x48, 0x04, + 0xaf, 0x01, 0x00, 0x00, 0xaf, 0x11, 0xed, 0x0e, + 0x0e, 0xe2, 0xc3, 0x05, 0xb7, 0x9e, 0x48, 0x04, + 0x28, 0x02, 0x00, 0x00, 0xaf, 0xed, 0x6a, 0xc3, + 0x06, 0xca, 0xeb, 0x9e, 0xc4, 0x06, 0x5f, 0x08, + 0x00, 0xca, 0xf1, 0x0e, 0x04, 0x34, 0x02, 0x00, + 0x00, 0xce, 0xc3, 0x08, 0xc3, 0x09, 0xb7, 0x9f, + 0xaf, 0xec, 0x11, 0x5f, 0x09, 0x00, 0x04, 0x95, + 0x01, 0x00, 0x00, 0xd3, 0xf2, 0x0e, 0xb6, 0xc4, + 0x08, 0xee, 0x2f, 0x5f, 0x09, 0x00, 0xc2, 0xc3, + 0x0b, 0xc3, 0x08, 0x92, 0xc4, 0x08, 0x48, 0xc3, + 0x06, 0x9f, 0xf2, 0x0e, 0xee, 0x1c, 0x11, 0x7f, + 0x7a, 0x74, 0x01, 0x00, 0x00, 0x05, 0x00, 0x82, + 0x02, 0x0e, 0x3e, 0x7a, 0x39, 0x02, 0x00, 0x00, + 0x06, 0x00, 0x82, 0x02, 0x0e, 0x3e, 0x85, 0xee, + 0x0a, 0x5f, 0x0a, 0x00, 0xd3, 0xc3, 0x05, 0xf2, + 0xee, 0xdd, 0x0e, 0x94, 0x05, 0xef, 0x72, 0xff, + 0xc3, 0x05, 0xc4, 0x04, 0xc3, 0x04, 0xc4, 0x05, + 0xc3, 0x05, 0xc8, 0xa7, 0xec, 0x43, 0x5f, 0x08, + 0x00, 0xca, 0xf1, 0x0e, 0x04, 0x34, 0x02, 0x00, + 0x00, 0xce, 0x5f, 0x09, 0x00, 0x04, 0x95, 0x01, + 0x00, 0x00, 0xd3, 0xf2, 0x0e, 0xee, 0x1c, 0x11, + 0x7f, 0x7a, 0x74, 0x01, 0x00, 0x00, 0x05, 0x00, + 0x82, 0x02, 0x0e, 0x3e, 0x7a, 0x39, 0x02, 0x00, + 0x00, 0x06, 0x00, 0x82, 0x02, 0x0e, 0x3e, 0x85, + 0xee, 0x0a, 0x5f, 0x0a, 0x00, 0xd3, 0xc3, 0x05, + 0xf2, 0xee, 0xdd, 0x0e, 0x94, 0x05, 0xee, 0xb9, + 0x5f, 0x09, 0x00, 0x04, 0x95, 0x01, 0x00, 0x00, + 0xd3, 0xb8, 0x9f, 0xdb, 0xf2, 0x0e, 0x5f, 0x05, + 0x00, 0xe2, 0xc8, 0x48, 0xf1, 0x0e, 0xc8, 0xdf, + 0x26, 0x02, 0x00, 0x28, 0xc1, 0x00, 0xcc, 0xc1, + 0x01, 0xc4, 0x0b, 0xc1, 0x02, 0xc4, 0x0c, 0xc1, + 0x03, 0xc4, 0x0d, 0xc1, 0x04, 0xc4, 0x0e, 0xc1, + 0x05, 0xc4, 0x0f, 0xc1, 0x06, 0xc4, 0x10, 0xc1, + 0x07, 0xc4, 0x11, 0xc1, 0x08, 0xc4, 0x12, 0xc1, + 0x09, 0xc4, 0x13, 0xc1, 0x0a, 0xc4, 0x14, 0xc1, + 0x0b, 0xc4, 0x15, 0xc1, 0x0c, 0xc4, 0x16, 0xc1, + 0x0d, 0xc4, 0x17, 0x0b, 0xcb, 0xd4, 0x98, 0x04, + 0x4a, 0x00, 0x00, 0x00, 0xaf, 0xec, 0x1c, 0xd4, + 0x07, 0xb0, 0xec, 0x17, 0xd4, 0xcf, 0x42, 0x45, + 0x02, 0x00, 0x00, 0xd8, 0xc7, 0x42, 0x46, 0x02, + 0x00, 0x00, 0xd9, 0xc7, 0x42, 0xf0, 0x00, 0x00, + 0x00, 0xda, 0xd4, 0x98, 0x04, 0x48, 0x00, 0x00, + 0x00, 0xb0, 0xec, 0x03, 0x09, 0xd8, 0xc8, 0xd5, + 0xb8, 0xf2, 0xd9, 0xc8, 0xd6, 0x0a, 0xf2, 0xda, + 0xc8, 0xc7, 0x42, 0xea, 0x01, 0x00, 0x00, 0x5f, + 0x10, 0x00, 0x43, 0x96, 0x01, 0x00, 0x00, 0x5f, + 0x11, 0x00, 0xbe, 0x50, 0x24, 0x02, 0x00, 0xf2, + 0xcd, 0xc8, 0xc7, 0x42, 0xeb, 0x01, 0x00, 0x00, + 0xbe, 0x64, 0xf2, 0xce, 0xc8, 0xc7, 0x42, 0xec, + 0x01, 0x00, 0x00, 0xca, 0xbe, 0x0a, 0x9e, 0xf2, + 0xc4, 0x04, 0xc8, 0xc7, 0x42, 0xed, 0x01, 0x00, + 0x00, 0xbe, 0x4e, 0xf2, 0xc4, 0x05, 0x0b, 0x26, + 0x01, 0x00, 0xc4, 0x06, 0x26, 0x00, 0x00, 0xc4, + 0x07, 0x26, 0x00, 0x00, 0xc4, 0x08, 0x26, 0x00, + 0x00, 0xc4, 0x09, 0x04, 0x8f, 0x01, 0x00, 0x00, + 0xc4, 0x0a, 0xc3, 0x0f, 0xd3, 0xb6, 0xf2, 0x0e, + 0xc3, 0x17, 0xb6, 0xb6, 0xf2, 0x0e, 0xc3, 0x10, + 0xc2, 0xf1, 0x0e, 0xc3, 0x09, 0x43, 0x5c, 0x00, + 0x00, 0x00, 0xc2, 0x25, 0x01, 0x00, 0x0c, 0x43, + 0x02, 0x01, 0xae, 0x05, 0x01, 0x00, 0x01, 0x07, + 0x05, 0x00, 0x3c, 0x01, 0xcc, 0x07, 0x00, 0x01, + 0x00, 0xce, 0x03, 0x00, 0x0c, 0xac, 0x05, 0x78, + 0x01, 0xee, 0x03, 0x19, 0x01, 0xea, 0x03, 0x17, + 0x01, 0xec, 0x03, 0x18, 0x01, 0x66, 0x00, 0x00, + 0x43, 0x8e, 0x01, 0x00, 0x00, 0xe0, 0x43, 0x47, + 0x02, 0x00, 0x00, 0xd3, 0x0b, 0xe1, 0x4d, 0x46, + 0x02, 0x00, 0x00, 0xe2, 0x4d, 0xf0, 0x00, 0x00, + 0x00, 0x5f, 0x04, 0x00, 0x4d, 0x45, 0x02, 0x00, + 0x00, 0x24, 0x02, 0x00, 0x24, 0x01, 0x00, 0x0e, + 0x66, 0x00, 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, + 0x04, 0x95, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xb0, 0x05, 0x01, + 0x05, 0x01, 0x06, 0x03, 0x00, 0xb4, 0x01, 0x06, + 0xf4, 0x05, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, + 0x00, 0x00, 0x8c, 0x04, 0x00, 0x01, 0x00, 0x90, + 0x09, 0x00, 0x02, 0x00, 0xc2, 0x07, 0x00, 0x03, + 0x00, 0x92, 0x09, 0x00, 0x04, 0x00, 0xb2, 0x05, + 0x7b, 0x01, 0xba, 0x05, 0x7f, 0x01, 0xce, 0x03, + 0x00, 0x0c, 0xd3, 0x04, 0x4a, 0x02, 0x00, 0x00, + 0xaf, 0xec, 0x06, 0xdf, 0xf0, 0x0e, 0x0a, 0x28, + 0xd3, 0xb6, 0x48, 0x04, 0xb4, 0x01, 0x00, 0x00, + 0xb0, 0xec, 0x0e, 0xd3, 0xb6, 0x48, 0x04, 0xaf, + 0x01, 0x00, 0x00, 0xb0, 0xec, 0x03, 0x09, 0x28, + 0xb7, 0xcb, 0xc7, 0xd3, 0xeb, 0xa7, 0xec, 0x10, + 0xd3, 0xc7, 0x48, 0x04, 0xd9, 0x01, 0x00, 0x00, + 0xb0, 0xec, 0x05, 0x94, 0x00, 0xee, 0xec, 0xd3, + 0x43, 0x90, 0x01, 0x00, 0x00, 0xb7, 0xc7, 0x24, + 0x02, 0x00, 0xcc, 0xb6, 0xcd, 0xe0, 0x7e, 0xee, + 0x21, 0xc4, 0x04, 0xc3, 0x04, 0x43, 0xc4, 0x01, + 0x00, 0x00, 0xc8, 0x24, 0x01, 0x00, 0xec, 0x12, + 0xe0, 0xc3, 0x04, 0x48, 0xce, 0x94, 0x02, 0xc3, + 0x04, 0xc8, 0xaf, 0xec, 0x05, 0xb6, 0xcd, 0xee, + 0x05, 0x81, 0xec, 0xde, 0x0e, 0x0e, 0xca, 0xec, + 0x1d, 0xc9, 0xb8, 0xa7, 0xec, 0x18, 0xca, 0xd3, + 0x43, 0x90, 0x01, 0x00, 0x00, 0xc7, 0x24, 0x01, + 0x00, 0x43, 0x4b, 0x02, 0x00, 0x00, 0x24, 0x00, + 0x00, 0xf1, 0x0e, 0xee, 0x20, 0x66, 0x02, 0x00, + 0x43, 0x8e, 0x01, 0x00, 0x00, 0x04, 0x4c, 0x02, + 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, 0xc8, + 0x04, 0x95, 0x01, 0x00, 0x00, 0x24, 0x02, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0x0a, 0x28, 0x0c, 0x43, + 0x02, 0x01, 0xb2, 0x05, 0x00, 0x01, 0x00, 0x07, + 0x09, 0x01, 0xdc, 0x01, 0x01, 0x9a, 0x09, 0x00, + 0x00, 0x00, 0xce, 0x03, 0x00, 0x0c, 0xf0, 0x03, + 0x1a, 0x01, 0xe8, 0x03, 0x16, 0x01, 0xf2, 0x03, + 0x1b, 0x01, 0xee, 0x03, 0x19, 0x01, 0xec, 0x03, + 0x18, 0x01, 0xea, 0x03, 0x17, 0x01, 0xe4, 0x03, + 0x14, 0x01, 0xe2, 0x03, 0x13, 0x01, 0x0c, 0x42, + 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x0f, 0x01, 0xa2, 0x06, 0x00, 0x01, 0x00, + 0xd3, 0xec, 0x07, 0x04, 0x7f, 0x00, 0x00, 0x00, + 0x28, 0x04, 0xd9, 0x01, 0x00, 0x00, 0x28, 0xc1, + 0x00, 0x4e, 0x4d, 0x02, 0x00, 0x00, 0xcb, 0x66, + 0x00, 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, 0x04, + 0x4e, 0x02, 0x00, 0x00, 0x04, 0x4f, 0x02, 0x00, + 0x00, 0x9e, 0xc7, 0xe0, 0xf1, 0x9e, 0x04, 0x50, + 0x02, 0x00, 0x00, 0x9e, 0x04, 0x51, 0x02, 0x00, + 0x00, 0x9e, 0xc7, 0xe0, 0x97, 0xf1, 0x9e, 0x04, + 0x52, 0x02, 0x00, 0x00, 0x9e, 0x04, 0x53, 0x02, + 0x00, 0x00, 0x9e, 0xc7, 0xe1, 0xf1, 0x9e, 0x04, + 0x54, 0x02, 0x00, 0x00, 0x9e, 0x04, 0x55, 0x02, + 0x00, 0x00, 0x9e, 0xc7, 0xe2, 0xf1, 0x9e, 0x04, + 0x56, 0x02, 0x00, 0x00, 0x9e, 0x04, 0x57, 0x02, + 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, 0x5f, + 0x04, 0x00, 0x04, 0x58, 0x02, 0x00, 0x00, 0x24, + 0x02, 0x00, 0x9e, 0x04, 0x59, 0x02, 0x00, 0x00, + 0x9e, 0xc7, 0x5f, 0x05, 0x00, 0xf1, 0x9e, 0x04, + 0x5a, 0x02, 0x00, 0x00, 0x9e, 0x04, 0x5b, 0x02, + 0x00, 0x00, 0x9e, 0xc7, 0x5f, 0x06, 0x00, 0xf1, + 0x9e, 0x04, 0x5c, 0x02, 0x00, 0x00, 0x9e, 0x04, + 0x5d, 0x02, 0x00, 0x00, 0x9e, 0xc7, 0x5f, 0x07, + 0x00, 0x5f, 0x08, 0x00, 0x42, 0x5e, 0x02, 0x00, + 0x00, 0xad, 0xf1, 0x9e, 0x04, 0x5f, 0x02, 0x00, + 0x00, 0x9e, 0x04, 0x60, 0x02, 0x00, 0x00, 0x9e, + 0xc7, 0x5f, 0x07, 0x00, 0x5f, 0x08, 0x00, 0x42, + 0x61, 0x02, 0x00, 0x00, 0xad, 0xf1, 0x9e, 0x04, + 0x62, 0x02, 0x00, 0x00, 0x9e, 0x04, 0x63, 0x02, + 0x00, 0x00, 0x9e, 0x04, 0x64, 0x02, 0x00, 0x00, + 0x9e, 0x04, 0x65, 0x02, 0x00, 0x00, 0x9e, 0x24, + 0x01, 0x00, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xb4, + 0x05, 0x01, 0x01, 0x01, 0x07, 0x01, 0x00, 0x5f, + 0x02, 0xd8, 0x06, 0x00, 0x01, 0x00, 0xcc, 0x09, + 0x04, 0x00, 0x03, 0xce, 0x03, 0x00, 0x0c, 0xd3, + 0x43, 0x67, 0x02, 0x00, 0x00, 0x04, 0xaf, 0x01, + 0x00, 0x00, 0x24, 0x01, 0x00, 0xd3, 0x43, 0x67, + 0x02, 0x00, 0x00, 0x04, 0xbb, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0xa8, 0xec, 0x09, 0xd3, 0x04, + 0x68, 0x02, 0x00, 0x00, 0x9e, 0xd7, 0x6d, 0x13, + 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x43, 0x69, + 0x02, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0x0e, + 0x0e, 0x29, 0xcb, 0x6d, 0x21, 0x00, 0x00, 0x00, + 0x66, 0x00, 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, + 0xc2, 0x43, 0x5d, 0x00, 0x00, 0x00, 0xc7, 0x04, + 0x95, 0x01, 0x00, 0x00, 0x24, 0x02, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0x0e, 0x29, 0x30, 0x0c, 0x43, + 0x02, 0x01, 0xb6, 0x05, 0x01, 0x00, 0x01, 0x03, + 0x02, 0x00, 0x10, 0x01, 0xcc, 0x09, 0x00, 0x01, + 0x00, 0xd0, 0x05, 0x8a, 0x01, 0x01, 0xce, 0x03, + 0x00, 0x0c, 0xdf, 0xf0, 0x0e, 0x66, 0x01, 0x00, + 0x43, 0x5b, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, + 0x00, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xb8, 0x05, + 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, 0x14, 0x02, + 0xd8, 0x06, 0x00, 0x01, 0x00, 0x80, 0x08, 0x00, + 0x01, 0x00, 0xd3, 0xec, 0x10, 0x04, 0x6a, 0x02, + 0x00, 0x00, 0x43, 0x7f, 0x01, 0x00, 0x00, 0xd3, + 0x24, 0x01, 0x00, 0x28, 0xd4, 0x28, 0x0c, 0x42, + 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, 0x02, + 0x00, 0x06, 0x01, 0xd8, 0x06, 0x00, 0x01, 0x00, + 0xf0, 0x03, 0x1a, 0x01, 0xb8, 0x05, 0x7e, 0x01, + 0xe0, 0xd3, 0x0a, 0xf2, 0xe3, 0x29, 0x0c, 0x42, + 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, 0x02, + 0x00, 0x07, 0x01, 0xd8, 0x06, 0x00, 0x01, 0x00, + 0xf0, 0x03, 0x1a, 0x01, 0xb8, 0x05, 0x7e, 0x01, + 0xe0, 0xd3, 0x0a, 0xf2, 0x97, 0xe3, 0x29, 0x0c, + 0x42, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, + 0x02, 0x00, 0x07, 0x01, 0xd8, 0x06, 0x00, 0x01, + 0x00, 0xe8, 0x03, 0x16, 0x01, 0xb8, 0x05, 0x7e, + 0x01, 0xe0, 0xd3, 0xdf, 0x97, 0xf2, 0xe3, 0x29, + 0x0c, 0x42, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x03, 0x02, 0x00, 0x07, 0x01, 0xd8, 0x06, 0x00, + 0x01, 0x00, 0xf2, 0x03, 0x1b, 0x01, 0xb8, 0x05, + 0x7e, 0x01, 0xe0, 0xd3, 0xdf, 0x97, 0xf2, 0xe3, + 0x29, 0x0c, 0x42, 0x02, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x02, 0x01, 0x00, 0x09, 0x01, 0xd8, 0x06, + 0x00, 0x01, 0x00, 0xee, 0x03, 0x19, 0x01, 0xd3, + 0x8e, 0x11, 0xed, 0x03, 0x0e, 0xb8, 0xe3, 0x29, + 0x0c, 0x42, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x03, 0x02, 0x00, 0x07, 0x01, 0xd8, 0x06, 0x00, + 0x01, 0x00, 0xec, 0x03, 0x18, 0x01, 0xb8, 0x05, + 0x7e, 0x01, 0xe0, 0xd3, 0xdf, 0x97, 0xf2, 0xe3, + 0x29, 0x0c, 0x42, 0x02, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x03, 0x02, 0x00, 0x07, 0x01, 0xd8, 0x06, + 0x00, 0x01, 0x00, 0xea, 0x03, 0x17, 0x01, 0xb8, + 0x05, 0x7e, 0x01, 0xe0, 0xd3, 0xdf, 0x97, 0xf2, + 0xe3, 0x29, 0x0c, 0x42, 0x02, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x08, 0x00, 0xe4, + 0x03, 0x14, 0x01, 0xe2, 0x03, 0x13, 0x01, 0xe0, + 0x42, 0x5e, 0x02, 0x00, 0x00, 0xe3, 0x29, 0x0c, + 0x42, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x08, 0x00, 0xe4, 0x03, 0x14, 0x01, + 0xe2, 0x03, 0x13, 0x01, 0xe0, 0x42, 0x61, 0x02, + 0x00, 0x00, 0xe3, 0x29, 0x0c, 0x42, 0x02, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x11, + 0x00, 0xce, 0x03, 0x00, 0x0c, 0x66, 0x00, 0x00, + 0x43, 0x8e, 0x01, 0x00, 0x00, 0x04, 0x6b, 0x02, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x29, 0x0c, 0x42, + 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, + 0x00, 0x04, 0x00, 0xb6, 0x05, 0x7d, 0x01, 0xdf, + 0xb6, 0xf1, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xbc, + 0x05, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x14, + 0x00, 0xce, 0x03, 0x00, 0x0c, 0xbe, 0x05, 0x81, + 0x01, 0x01, 0x66, 0x00, 0x00, 0x43, 0x8e, 0x01, + 0x00, 0x00, 0x04, 0x6c, 0x02, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0xe0, 0xf0, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0xbe, 0x05, 0x00, 0x00, 0x00, 0x04, + 0x04, 0x00, 0x0c, 0x00, 0xa2, 0x05, 0x73, 0x01, + 0x98, 0x05, 0x6e, 0x01, 0x8a, 0x04, 0x27, 0x01, + 0xc0, 0x05, 0x82, 0x01, 0x01, 0xdf, 0xe0, 0x04, + 0x6d, 0x02, 0x00, 0x00, 0xe1, 0xf2, 0xe2, 0xf2, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xc0, 0x05, 0x01, + 0x00, 0x01, 0x02, 0x02, 0x00, 0x0a, 0x01, 0xdc, + 0x09, 0x00, 0x01, 0x00, 0xc2, 0x05, 0x83, 0x01, + 0x01, 0xbe, 0x05, 0x81, 0x01, 0x01, 0xdf, 0xd3, + 0xf1, 0x97, 0xec, 0x04, 0xe0, 0xf0, 0x0e, 0x29, + 0x0c, 0x43, 0x02, 0x01, 0xc2, 0x05, 0x01, 0x01, + 0x01, 0x02, 0x06, 0x00, 0x3a, 0x02, 0xdc, 0x09, + 0x00, 0x01, 0x00, 0xb4, 0x06, 0x00, 0x00, 0x00, + 0x88, 0x04, 0x26, 0x01, 0xb0, 0x05, 0x7a, 0x01, + 0xcc, 0x05, 0x88, 0x01, 0x01, 0xfa, 0x03, 0x1f, + 0x01, 0x8a, 0x04, 0x27, 0x01, 0xc4, 0x05, 0x84, + 0x01, 0x01, 0xd3, 0x97, 0xec, 0x03, 0x09, 0x28, + 0xdf, 0xec, 0x0d, 0xdf, 0x04, 0x95, 0x01, 0x00, + 0x00, 0x9e, 0xd3, 0x9e, 0xd7, 0xee, 0x08, 0xe0, + 0xd3, 0xf1, 0xec, 0x03, 0x09, 0x28, 0xe1, 0xd3, + 0xf1, 0xcf, 0xb6, 0x48, 0xe6, 0xc7, 0xb7, 0x48, + 0x60, 0x04, 0x00, 0xe2, 0xec, 0x05, 0xd3, 0xe3, + 0x09, 0x28, 0xc2, 0xe3, 0x5f, 0x05, 0x00, 0xd3, + 0xf1, 0x0e, 0x0a, 0x28, 0x0c, 0x43, 0x02, 0x01, + 0xc4, 0x05, 0x01, 0x01, 0x01, 0x06, 0x06, 0x00, + 0x4a, 0x02, 0xdc, 0x09, 0x00, 0x01, 0x00, 0xde, + 0x09, 0x00, 0x00, 0x00, 0xf2, 0x03, 0x1b, 0x01, + 0x84, 0x04, 0x24, 0x01, 0xd0, 0x03, 0x01, 0x0c, + 0xce, 0x03, 0x00, 0x0c, 0xc6, 0x05, 0x85, 0x01, + 0x01, 0xc8, 0x05, 0x86, 0x01, 0x01, 0xdf, 0xec, + 0x09, 0x04, 0x70, 0x02, 0x00, 0x00, 0xd3, 0x9e, + 0xd7, 0x66, 0x02, 0x00, 0x43, 0x71, 0x02, 0x00, + 0x00, 0x24, 0x00, 0x00, 0xe4, 0x39, 0xc4, 0x00, + 0x00, 0x00, 0x43, 0x18, 0x00, 0x00, 0x00, 0x66, + 0x03, 0x00, 0x42, 0x72, 0x02, 0x00, 0x00, 0xd3, + 0x0b, 0x0a, 0x4d, 0x73, 0x02, 0x00, 0x00, 0x0a, + 0x4d, 0x87, 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, + 0xcf, 0x43, 0x81, 0x00, 0x00, 0x00, 0x5f, 0x04, + 0x00, 0x5f, 0x05, 0x00, 0x24, 0x02, 0x00, 0x29, + 0x0c, 0x43, 0x02, 0x01, 0xc6, 0x05, 0x01, 0x00, + 0x01, 0x02, 0x06, 0x00, 0x27, 0x01, 0xde, 0x09, + 0x00, 0x01, 0x00, 0x86, 0x04, 0x25, 0x01, 0xd0, + 0x03, 0x01, 0x0c, 0x84, 0x04, 0x24, 0x01, 0xae, + 0x05, 0x79, 0x01, 0xd4, 0x03, 0x00, 0x03, 0xca, + 0x05, 0x87, 0x01, 0x01, 0xd3, 0x42, 0x41, 0x00, + 0x00, 0x00, 0xd7, 0x66, 0x01, 0x00, 0x43, 0x71, + 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, 0xe1, 0x9f, + 0xe3, 0xe2, 0xd3, 0xf1, 0x0e, 0x5f, 0x04, 0x00, + 0xd3, 0x44, 0x7c, 0x01, 0x00, 0x00, 0x5f, 0x05, + 0x00, 0xf0, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xc8, + 0x05, 0x01, 0x00, 0x01, 0x04, 0x06, 0x00, 0xa1, + 0x01, 0x01, 0xe8, 0x09, 0x00, 0x01, 0x00, 0xea, + 0x03, 0x17, 0x01, 0xce, 0x03, 0x00, 0x0c, 0xe0, + 0x03, 0x12, 0x01, 0xe4, 0x03, 0x14, 0x01, 0xac, + 0x02, 0x09, 0x01, 0xca, 0x05, 0x87, 0x01, 0x01, + 0xdf, 0xec, 0x15, 0x66, 0x01, 0x00, 0x43, 0x8e, + 0x01, 0x00, 0x00, 0xe1, 0xe2, 0x42, 0x74, 0x02, + 0x00, 0x00, 0x48, 0x24, 0x01, 0x00, 0x0e, 0xd3, + 0x5f, 0x04, 0x00, 0xab, 0xec, 0x3b, 0x66, 0x01, + 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0x0e, 0x66, 0x01, 0x00, 0x43, 0x8e, + 0x01, 0x00, 0x00, 0x04, 0x95, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xd3, 0x42, 0x36, 0x00, + 0x00, 0x00, 0xec, 0x44, 0x66, 0x01, 0x00, 0x43, + 0x8e, 0x01, 0x00, 0x00, 0xd3, 0x42, 0x36, 0x00, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xee, 0x30, + 0x66, 0x01, 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, + 0x04, 0x75, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0x66, 0x01, 0x00, 0x43, 0x8e, 0x01, 0x00, + 0x00, 0xd3, 0x24, 0x01, 0x00, 0x0e, 0x66, 0x01, + 0x00, 0x43, 0x8e, 0x01, 0x00, 0x00, 0x04, 0x95, + 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xdf, + 0xec, 0x13, 0x66, 0x01, 0x00, 0x43, 0x8e, 0x01, + 0x00, 0x00, 0xe1, 0x42, 0x8f, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0x5f, 0x05, 0x00, 0xf0, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xca, 0x05, 0x00, + 0x00, 0x00, 0x02, 0x03, 0x00, 0x11, 0x00, 0x8a, + 0x04, 0x27, 0x01, 0xce, 0x03, 0x00, 0x0c, 0xbe, + 0x05, 0x81, 0x01, 0x01, 0xb6, 0xe3, 0x66, 0x01, + 0x00, 0x43, 0x76, 0x02, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x0e, 0xe1, 0xf0, 0x29, 0x0c, 0x43, 0x02, + 0x01, 0xcc, 0x05, 0x01, 0x17, 0x01, 0x04, 0x03, + 0x0a, 0x84, 0x04, 0x18, 0x80, 0x06, 0x00, 0x01, + 0x40, 0xe8, 0x05, 0x00, 0x00, 0x40, 0xee, 0x05, + 0x00, 0x01, 0x40, 0x94, 0x06, 0x00, 0x02, 0x40, + 0xa2, 0x06, 0x00, 0x03, 0x40, 0x9a, 0x06, 0x00, + 0x04, 0x40, 0xee, 0x09, 0x00, 0x05, 0x40, 0x8a, + 0x04, 0x00, 0x06, 0x00, 0xf0, 0x09, 0x00, 0x07, + 0x00, 0xf2, 0x09, 0x00, 0x08, 0x40, 0xfc, 0x06, + 0x00, 0x09, 0x40, 0xf4, 0x09, 0x00, 0x0a, 0x40, + 0xf6, 0x09, 0x00, 0x0b, 0x40, 0xf8, 0x09, 0x00, + 0x0c, 0x40, 0xfa, 0x09, 0x00, 0x0d, 0x00, 0xfc, + 0x09, 0x00, 0x0e, 0x00, 0xfe, 0x09, 0x00, 0x0f, + 0x00, 0x80, 0x0a, 0x00, 0x10, 0x00, 0x82, 0x0a, + 0x00, 0x11, 0x00, 0x84, 0x0a, 0x00, 0x12, 0x40, + 0x86, 0x0a, 0x00, 0x13, 0x40, 0x88, 0x0a, 0x00, + 0x14, 0x40, 0x8a, 0x0a, 0x00, 0x15, 0x00, 0x8c, + 0x0a, 0x00, 0x16, 0x00, 0xb2, 0x04, 0x3b, 0x01, + 0xba, 0x04, 0x3f, 0x01, 0xb0, 0x04, 0x3a, 0x01, + 0x0c, 0x43, 0x02, 0x01, 0xf4, 0x09, 0x01, 0x00, + 0x01, 0x02, 0x01, 0x00, 0x05, 0x01, 0xee, 0x05, + 0x00, 0x01, 0x00, 0xee, 0x09, 0x05, 0x01, 0xdf, + 0xd3, 0x9e, 0xe3, 0x29, 0x0c, 0x43, 0x02, 0x01, + 0xf6, 0x09, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, + 0x0d, 0x01, 0xee, 0x05, 0x00, 0x01, 0x00, 0xee, + 0x09, 0x05, 0x01, 0xdf, 0x43, 0x90, 0x01, 0x00, + 0x00, 0xdf, 0xeb, 0xb7, 0x9f, 0x25, 0x01, 0x00, + 0x0c, 0x43, 0x02, 0x01, 0xf8, 0x09, 0x01, 0x00, + 0x01, 0x05, 0x02, 0x00, 0x14, 0x01, 0xee, 0x05, + 0x00, 0x01, 0x00, 0xf6, 0x09, 0x0b, 0x01, 0xee, + 0x09, 0x05, 0x01, 0xdf, 0xf0, 0xd7, 0xe0, 0x43, + 0x90, 0x01, 0x00, 0x00, 0xb6, 0xe0, 0xeb, 0xb7, + 0x9f, 0x24, 0x02, 0x00, 0xe4, 0xd3, 0x28, 0x0c, + 0x43, 0x02, 0x01, 0xfa, 0x09, 0x00, 0x00, 0x00, + 0x03, 0x06, 0x00, 0x49, 0x00, 0x9a, 0x06, 0x04, + 0x01, 0xf4, 0x09, 0x0a, 0x01, 0xe8, 0x05, 0x00, + 0x01, 0xa2, 0x06, 0x03, 0x01, 0x80, 0x06, 0x00, + 0x03, 0xf8, 0x09, 0x0c, 0x01, 0x04, 0x87, 0x02, + 0x00, 0x00, 0xe3, 0xe0, 0x04, 0xbb, 0x01, 0x00, + 0x00, 0xf1, 0x0e, 0xe1, 0x90, 0xe5, 0xe1, 0xe2, + 0xb7, 0x9f, 0xa7, 0xec, 0x31, 0x5f, 0x04, 0x00, + 0xe1, 0x48, 0x04, 0x7f, 0x00, 0x00, 0x00, 0xad, + 0xec, 0x1f, 0x5f, 0x04, 0x00, 0xe1, 0xb7, 0x9e, + 0x48, 0x04, 0xbb, 0x01, 0x00, 0x00, 0xad, 0xec, + 0x10, 0xe1, 0xb8, 0x9e, 0xe5, 0x5f, 0x05, 0x00, + 0x04, 0xbb, 0x01, 0x00, 0x00, 0xf1, 0x0e, 0x29, + 0xe1, 0x90, 0xe5, 0xee, 0xca, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0xfc, 0x09, 0x00, 0x00, 0x00, 0x02, + 0x04, 0x00, 0x1f, 0x00, 0x9a, 0x06, 0x04, 0x01, + 0xe8, 0x05, 0x00, 0x01, 0xa2, 0x06, 0x03, 0x01, + 0x80, 0x06, 0x00, 0x03, 0x04, 0x87, 0x02, 0x00, + 0x00, 0xe3, 0xe0, 0x90, 0xe4, 0xe0, 0xe1, 0xa7, + 0xec, 0x11, 0xe2, 0xe0, 0x48, 0x04, 0x95, 0x01, + 0x00, 0x00, 0xad, 0xed, 0x06, 0xe0, 0x90, 0xe4, + 0xee, 0xec, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xfe, + 0x09, 0x01, 0x00, 0x01, 0x03, 0x07, 0x00, 0x4c, + 0x01, 0x90, 0x0a, 0x00, 0x01, 0x00, 0x9a, 0x06, + 0x04, 0x01, 0xf4, 0x09, 0x0a, 0x01, 0xe8, 0x05, + 0x00, 0x01, 0xa2, 0x06, 0x03, 0x01, 0xee, 0x05, + 0x01, 0x01, 0x80, 0x06, 0x00, 0x03, 0xf8, 0x09, + 0x0c, 0x01, 0x04, 0x49, 0x00, 0x00, 0x00, 0xe3, + 0xe0, 0xd3, 0xf1, 0x0e, 0xe1, 0xe2, 0xa7, 0xec, + 0x3d, 0x5f, 0x05, 0x00, 0xe1, 0x92, 0xe5, 0x48, + 0x61, 0x04, 0x00, 0x04, 0x95, 0x01, 0x00, 0x00, + 0xad, 0xec, 0x09, 0x04, 0x74, 0x02, 0x00, 0x00, + 0xe3, 0xee, 0xe2, 0x5f, 0x04, 0x00, 0x04, 0xb4, + 0x01, 0x00, 0x00, 0xad, 0xec, 0x0b, 0xe1, 0xe2, + 0xaa, 0xed, 0x13, 0xe1, 0x90, 0xe5, 0xee, 0xcd, + 0x5f, 0x04, 0x00, 0xd3, 0xad, 0xec, 0xc6, 0x5f, + 0x06, 0x00, 0xf0, 0x0e, 0x29, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0x80, 0x0a, 0x00, 0x00, 0x00, 0x03, + 0x09, 0x00, 0xc4, 0x01, 0x00, 0x9a, 0x06, 0x04, + 0x01, 0xf4, 0x09, 0x0a, 0x01, 0xe8, 0x05, 0x00, + 0x01, 0xa2, 0x06, 0x03, 0x01, 0xee, 0x05, 0x01, + 0x01, 0x80, 0x06, 0x00, 0x03, 0xf6, 0x09, 0x0b, + 0x01, 0xf8, 0x09, 0x0c, 0x01, 0xb2, 0x04, 0x00, + 0x00, 0x04, 0x32, 0x02, 0x00, 0x00, 0xe3, 0xe0, + 0x04, 0xbb, 0x01, 0x00, 0x00, 0xf1, 0x0e, 0xe1, + 0xe2, 0xa7, 0x6a, 0xb1, 0x00, 0x00, 0x00, 0x5f, + 0x05, 0x00, 0xe1, 0x92, 0xe5, 0x48, 0x61, 0x04, + 0x00, 0x04, 0x95, 0x01, 0x00, 0x00, 0xad, 0xec, + 0x09, 0x04, 0x74, 0x02, 0x00, 0x00, 0xe3, 0xee, + 0xdf, 0x5f, 0x04, 0x00, 0x04, 0xb4, 0x01, 0x00, + 0x00, 0xad, 0xec, 0x0b, 0xe1, 0xe2, 0xa7, 0xec, + 0xcf, 0xe1, 0x90, 0xe5, 0xee, 0xca, 0x5f, 0x06, + 0x00, 0xf0, 0x04, 0xde, 0x01, 0x00, 0x00, 0xad, + 0xec, 0x13, 0x5f, 0x04, 0x00, 0x04, 0xba, 0x01, + 0x00, 0x00, 0xad, 0xec, 0xb3, 0x5f, 0x07, 0x00, + 0xf0, 0x0e, 0xee, 0xac, 0x5f, 0x04, 0x00, 0x04, + 0xde, 0x01, 0x00, 0x00, 0xad, 0xec, 0x2e, 0xe0, + 0x04, 0xde, 0x01, 0x00, 0x00, 0xf1, 0x0e, 0x5f, + 0x05, 0x00, 0xe1, 0x48, 0x04, 0xde, 0x01, 0x00, + 0x00, 0xad, 0x11, 0xed, 0x0d, 0x0e, 0x5f, 0x05, + 0x00, 0xe1, 0x48, 0x04, 0xba, 0x01, 0x00, 0x00, + 0xad, 0x6a, 0x7d, 0xff, 0xff, 0xff, 0xe1, 0x90, + 0xe5, 0xef, 0x75, 0xff, 0x5f, 0x04, 0x00, 0x04, + 0xbb, 0x01, 0x00, 0x00, 0xad, 0x6a, 0x69, 0xff, + 0xff, 0xff, 0x5f, 0x07, 0x00, 0xf0, 0x0e, 0xe1, + 0xe2, 0xa7, 0xec, 0x11, 0x5f, 0x08, 0x00, 0x5f, + 0x05, 0x00, 0xe1, 0x48, 0xf1, 0xec, 0x06, 0xe1, + 0x90, 0xe5, 0xee, 0xec, 0x29, 0x0c, 0x43, 0x02, + 0x01, 0x82, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x05, + 0x00, 0x41, 0x00, 0x9a, 0x06, 0x04, 0x01, 0xe8, + 0x05, 0x00, 0x01, 0xa2, 0x06, 0x03, 0x01, 0xb2, + 0x04, 0x00, 0x00, 0x80, 0x06, 0x00, 0x03, 0x04, + 0x47, 0x00, 0x00, 0x00, 0xe3, 0xe0, 0xe1, 0xa7, + 0xec, 0x36, 0xe2, 0x5f, 0x04, 0x00, 0xe0, 0x48, + 0xf1, 0x11, 0xed, 0x25, 0x0e, 0x5f, 0x04, 0x00, + 0xe0, 0x48, 0x04, 0xaf, 0x01, 0x00, 0x00, 0xad, + 0xec, 0x1e, 0xe0, 0xe1, 0xb7, 0x9f, 0xad, 0x11, + 0xed, 0x0f, 0x0e, 0x5f, 0x04, 0x00, 0xe0, 0xb7, + 0x9e, 0x48, 0x04, 0xaf, 0x01, 0x00, 0x00, 0xae, + 0xec, 0x06, 0xe0, 0x90, 0xe4, 0xee, 0xc7, 0x29, + 0x0c, 0x43, 0x02, 0x01, 0x8a, 0x0a, 0x00, 0x03, + 0x00, 0x04, 0x0a, 0x00, 0x95, 0x02, 0x03, 0xd8, + 0x06, 0x00, 0x00, 0x00, 0xf2, 0x08, 0x00, 0x01, + 0x00, 0x92, 0x0a, 0x00, 0x02, 0x00, 0xf2, 0x09, + 0x08, 0x01, 0xe8, 0x05, 0x00, 0x01, 0xa2, 0x06, + 0x03, 0x01, 0xb2, 0x04, 0x00, 0x00, 0x80, 0x06, + 0x00, 0x03, 0x94, 0x06, 0x02, 0x01, 0x84, 0x0a, + 0x12, 0x01, 0x9a, 0x06, 0x04, 0x01, 0x86, 0x0a, + 0x13, 0x01, 0x88, 0x0a, 0x14, 0x01, 0xb7, 0xe3, + 0xe0, 0xe1, 0xa7, 0xec, 0x0f, 0xe2, 0x5f, 0x04, + 0x00, 0xe0, 0x48, 0xf1, 0xec, 0x06, 0xe0, 0x90, + 0xe4, 0xee, 0xee, 0x5f, 0x04, 0x00, 0x43, 0x90, + 0x01, 0x00, 0x00, 0x5f, 0x05, 0x00, 0xe0, 0x24, + 0x02, 0x00, 0xcb, 0x04, 0x8a, 0x02, 0x00, 0x00, + 0xc7, 0x9e, 0x04, 0x8a, 0x02, 0x00, 0x00, 0x9e, + 0xcc, 0x5f, 0x06, 0x00, 0x43, 0xb6, 0x01, 0x00, + 0x00, 0xc8, 0x24, 0x01, 0x00, 0xb6, 0xaa, 0xec, + 0x7c, 0x04, 0x38, 0x02, 0x00, 0x00, 0x60, 0x07, + 0x00, 0xc7, 0x04, 0x03, 0x00, 0x00, 0x00, 0xaf, + 0x11, 0xed, 0x09, 0x0e, 0xc7, 0x04, 0x02, 0x00, + 0x00, 0x00, 0xaf, 0xec, 0x0b, 0x04, 0x48, 0x00, + 0x00, 0x00, 0x60, 0x07, 0x00, 0xee, 0x43, 0xc7, + 0x04, 0x03, 0x00, 0x00, 0x00, 0xaf, 0x11, 0xed, + 0x09, 0x0e, 0xc7, 0x04, 0x02, 0x00, 0x00, 0x00, + 0xaf, 0xec, 0x0b, 0x04, 0x48, 0x00, 0x00, 0x00, + 0x60, 0x07, 0x00, 0xee, 0x25, 0xc7, 0x04, 0x01, + 0x00, 0x00, 0x00, 0xaf, 0xec, 0x0b, 0x04, 0x01, + 0x00, 0x00, 0x00, 0x60, 0x07, 0x00, 0xee, 0x12, + 0xc7, 0x04, 0x46, 0x00, 0x00, 0x00, 0xaf, 0xec, + 0x09, 0x04, 0x46, 0x00, 0x00, 0x00, 0x60, 0x07, + 0x00, 0x5f, 0x08, 0x00, 0x43, 0xb6, 0x01, 0x00, + 0x00, 0xc8, 0x24, 0x01, 0x00, 0xb6, 0xaa, 0xec, + 0x03, 0xb6, 0xe3, 0x29, 0xe0, 0xcd, 0xc9, 0xe1, + 0xa7, 0xec, 0x12, 0x5f, 0x04, 0x00, 0xc9, 0x48, + 0x04, 0xd9, 0x01, 0x00, 0x00, 0xad, 0xec, 0x05, + 0x94, 0x02, 0xee, 0xeb, 0xc9, 0xe1, 0xa7, 0xec, + 0x17, 0x5f, 0x04, 0x00, 0xc9, 0x48, 0x04, 0xd0, + 0x01, 0x00, 0x00, 0xad, 0xec, 0x0a, 0x04, 0x1b, + 0x00, 0x00, 0x00, 0x60, 0x07, 0x00, 0x29, 0x5f, + 0x09, 0x00, 0x43, 0xb6, 0x01, 0x00, 0x00, 0xc8, + 0x24, 0x01, 0x00, 0xb6, 0xaa, 0xec, 0x0a, 0x04, + 0x09, 0x02, 0x00, 0x00, 0x60, 0x07, 0x00, 0x29, + 0x04, 0x8b, 0x02, 0x00, 0x00, 0x60, 0x07, 0x00, + 0xb6, 0xe3, 0x29, 0x0c, 0x43, 0x02, 0x01, 0x8c, + 0x0a, 0x02, 0x00, 0x02, 0x03, 0x02, 0x00, 0x2b, + 0x02, 0xf6, 0x01, 0x00, 0x01, 0x00, 0x98, 0x0a, + 0x00, 0x01, 0x00, 0xfc, 0x06, 0x09, 0x01, 0x9a, + 0x06, 0x04, 0x01, 0xdf, 0xeb, 0xd3, 0xa7, 0xec, + 0x12, 0xdf, 0x43, 0xa3, 0x01, 0x00, 0x00, 0x04, + 0x16, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, + 0xee, 0xea, 0xdf, 0xeb, 0xd4, 0xa7, 0xec, 0x0e, + 0xdf, 0x43, 0xa3, 0x01, 0x00, 0x00, 0xe0, 0x24, + 0x01, 0x00, 0x0e, 0xee, 0xee, 0x29, 0xc1, 0x00, + 0xc4, 0x0a, 0xc1, 0x01, 0xc4, 0x0b, 0xc1, 0x02, + 0xc4, 0x0c, 0xc1, 0x03, 0xc4, 0x0d, 0xc1, 0x04, + 0xc4, 0x0e, 0xc1, 0x05, 0xc4, 0x0f, 0xc1, 0x06, + 0xc4, 0x10, 0xc1, 0x07, 0xc4, 0x11, 0xc1, 0x08, + 0xc4, 0x15, 0xc1, 0x09, 0xc4, 0x16, 0xd3, 0xeb, + 0xce, 0xc2, 0xc4, 0x05, 0xb6, 0xc4, 0x06, 0xb7, + 0xc4, 0x08, 0x26, 0x00, 0x00, 0xc4, 0x09, 0x04, + 0x8a, 0x02, 0x00, 0x00, 0x04, 0x8d, 0x02, 0x00, + 0x00, 0x9e, 0x04, 0x8e, 0x02, 0x00, 0x00, 0x9e, + 0x04, 0x8f, 0x02, 0x00, 0x00, 0x9e, 0x04, 0x90, + 0x02, 0x00, 0x00, 0x9e, 0x04, 0x91, 0x02, 0x00, + 0x00, 0x9e, 0x04, 0x92, 0x02, 0x00, 0x00, 0x9e, + 0x04, 0x93, 0x02, 0x00, 0x00, 0x9e, 0x04, 0x94, + 0x02, 0x00, 0x00, 0x9e, 0x04, 0x95, 0x02, 0x00, + 0x00, 0x9e, 0xc4, 0x12, 0x04, 0x96, 0x02, 0x00, + 0x00, 0xc4, 0x13, 0x04, 0x97, 0x02, 0x00, 0x00, + 0xc4, 0x14, 0xb6, 0xcb, 0xc7, 0xca, 0xa7, 0x6a, + 0x6a, 0x01, 0x00, 0x00, 0x07, 0xc4, 0x04, 0xc7, + 0xcd, 0xd3, 0xc7, 0x92, 0xcb, 0x48, 0xd0, 0x11, + 0x04, 0xd9, 0x01, 0x00, 0x00, 0xaf, 0xed, 0x1c, + 0x11, 0x04, 0x98, 0x02, 0x00, 0x00, 0xaf, 0xed, + 0x13, 0x11, 0x04, 0x99, 0x02, 0x00, 0x00, 0xaf, + 0xed, 0x0a, 0x11, 0x04, 0x95, 0x01, 0x00, 0x00, + 0xaf, 0xec, 0x04, 0x0e, 0xee, 0xc7, 0x11, 0x04, + 0x9a, 0x02, 0x00, 0x00, 0xaf, 0xed, 0x0a, 0x11, + 0x04, 0xe4, 0x01, 0x00, 0x00, 0xaf, 0xec, 0x18, + 0xc7, 0xca, 0xa7, 0xec, 0x0d, 0xd3, 0xc7, 0x48, + 0xc8, 0xad, 0xec, 0x06, 0x94, 0x00, 0x0e, 0xee, + 0xa4, 0xb7, 0xc4, 0x08, 0x0e, 0xee, 0x9e, 0x11, + 0x04, 0xbb, 0x01, 0x00, 0x00, 0xaf, 0xec, 0x44, + 0xc7, 0xca, 0xa7, 0xec, 0x13, 0xd3, 0xc7, 0x48, + 0x04, 0x7f, 0x00, 0x00, 0x00, 0xad, 0xec, 0x08, + 0xc3, 0x0d, 0xf0, 0x0e, 0xef, 0xdc, 0x00, 0xc7, + 0xca, 0xa7, 0xec, 0x13, 0xd3, 0xc7, 0x48, 0x04, + 0xbb, 0x01, 0x00, 0x00, 0xad, 0xec, 0x08, 0xc3, + 0x0e, 0xf0, 0x0e, 0xef, 0xc5, 0x00, 0xc3, 0x08, + 0xec, 0x0b, 0xc3, 0x10, 0xf0, 0x0e, 0xb6, 0xc4, + 0x08, 0xef, 0xb7, 0x00, 0xb7, 0xc4, 0x08, 0x0e, + 0xef, 0x53, 0xff, 0x11, 0x04, 0xb7, 0x01, 0x00, + 0x00, 0xaf, 0xed, 0x13, 0x11, 0x04, 0xb8, 0x01, + 0x00, 0x00, 0xaf, 0xed, 0x0a, 0x11, 0x04, 0xb9, + 0x01, 0x00, 0x00, 0xaf, 0xec, 0x0c, 0xc3, 0x0f, + 0xc8, 0xf1, 0x0e, 0xb6, 0xc4, 0x08, 0xef, 0x8a, + 0x00, 0x11, 0x04, 0xd0, 0x01, 0x00, 0x00, 0xaf, + 0xed, 0x13, 0x11, 0x04, 0xde, 0x01, 0x00, 0x00, + 0xaf, 0xed, 0x0a, 0x11, 0x04, 0x21, 0x02, 0x00, + 0x00, 0xaf, 0xec, 0x0f, 0xb7, 0xc4, 0x08, 0x94, + 0x06, 0xc3, 0x0a, 0xc8, 0xf1, 0x0e, 0x0e, 0xef, + 0x04, 0xff, 0x11, 0x04, 0xd1, 0x01, 0x00, 0x00, + 0xaf, 0xed, 0x13, 0x11, 0x04, 0xba, 0x01, 0x00, + 0x00, 0xaf, 0xed, 0x0a, 0x11, 0x04, 0x22, 0x02, + 0x00, 0x00, 0xaf, 0xec, 0x25, 0xb6, 0xc4, 0x08, + 0xc3, 0x06, 0xb6, 0xa9, 0xec, 0x13, 0xe0, 0xc3, + 0x0b, 0xf0, 0xc8, 0xf2, 0xec, 0x0b, 0x93, 0x06, + 0xc3, 0x0c, 0xf0, 0x0e, 0x0e, 0xef, 0xce, 0xfe, + 0x04, 0x74, 0x02, 0x00, 0x00, 0xc4, 0x04, 0xee, + 0x21, 0xe1, 0xc8, 0xf1, 0xec, 0x0a, 0xc3, 0x11, + 0xf0, 0x0e, 0xb6, 0xc4, 0x08, 0xee, 0x13, 0xdf, + 0xc8, 0xf1, 0xec, 0x07, 0xc3, 0x15, 0xf0, 0x0e, + 0xee, 0x08, 0xb7, 0xc4, 0x08, 0x0e, 0xef, 0xa5, + 0xfe, 0x0e, 0xc3, 0x04, 0x6a, 0x9f, 0xfe, 0xff, + 0xff, 0xc3, 0x16, 0xc9, 0xc7, 0xf2, 0x0e, 0xef, + 0x94, 0xfe, 0xc3, 0x16, 0xca, 0xca, 0xf2, 0x0e, + 0xc3, 0x05, 0xc3, 0x06, 0xc3, 0x09, 0x26, 0x03, + 0x00, 0x28, 0x0c, 0x43, 0x02, 0x01, 0xce, 0x05, + 0x01, 0x02, 0x01, 0x04, 0x02, 0x00, 0x9d, 0x01, + 0x03, 0xd8, 0x06, 0x00, 0x01, 0x00, 0xb6, 0x0a, + 0x00, 0x00, 0x00, 0xb8, 0x0a, 0x00, 0x01, 0x00, + 0xce, 0x03, 0x00, 0x0c, 0xd0, 0x03, 0x01, 0x0c, + 0x66, 0x00, 0x00, 0x43, 0x9d, 0x02, 0x00, 0x00, + 0x04, 0x9e, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0xcf, 0xec, 0x16, 0xc7, 0xb6, 0x48, 0x04, 0xbb, + 0x01, 0x00, 0x00, 0xaf, 0xec, 0x0b, 0xc7, 0x04, + 0xbb, 0x01, 0x00, 0x00, 0x9e, 0xd3, 0x9e, 0x28, + 0x66, 0x00, 0x00, 0x43, 0x9d, 0x02, 0x00, 0x00, + 0x04, 0x9f, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0xcc, 0x66, 0x01, 0x00, 0x42, 0xa0, 0x02, 0x00, + 0x00, 0x04, 0xa1, 0x02, 0x00, 0x00, 0xaf, 0xec, + 0x0c, 0xc8, 0xec, 0x09, 0xc8, 0x04, 0xa2, 0x02, + 0x00, 0x00, 0x9e, 0xcb, 0x66, 0x01, 0x00, 0x43, + 0xa3, 0x02, 0x00, 0x00, 0xc7, 0x04, 0xbb, 0x01, + 0x00, 0x00, 0x9e, 0x24, 0x01, 0x00, 0xb7, 0x48, + 0xb6, 0xaf, 0xec, 0x0b, 0xc7, 0x04, 0xbb, 0x01, + 0x00, 0x00, 0x9e, 0xd3, 0x9e, 0x28, 0xc8, 0x11, + 0xed, 0x1b, 0x0e, 0x66, 0x00, 0x00, 0x43, 0x9d, + 0x02, 0x00, 0x00, 0x04, 0xa4, 0x02, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x11, 0xed, 0x07, 0x0e, 0x04, + 0xaf, 0x01, 0x00, 0x00, 0x04, 0xa5, 0x02, 0x00, + 0x00, 0x9e, 0xd3, 0x9e, 0x28, 0x0c, 0x43, 0x02, + 0x01, 0xd0, 0x05, 0x00, 0x03, 0x00, 0x05, 0x03, + 0x00, 0x67, 0x03, 0xd8, 0x06, 0x00, 0x00, 0x00, + 0xcc, 0x0a, 0x00, 0x01, 0x00, 0xcc, 0x09, 0x05, + 0x00, 0x03, 0xf4, 0x03, 0x1c, 0x01, 0xce, 0x03, + 0x00, 0x0c, 0xce, 0x05, 0x89, 0x01, 0x01, 0xdf, + 0x43, 0xb0, 0x01, 0x00, 0x00, 0xbf, 0x18, 0xfc, + 0x24, 0x01, 0x00, 0x43, 0x5c, 0x00, 0x00, 0x00, + 0x04, 0x95, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x43, 0x4b, 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xcf, 0xec, 0x43, 0x6d, 0x38, 0x00, 0x00, 0x00, + 0x66, 0x01, 0x00, 0x43, 0xa7, 0x02, 0x00, 0x00, + 0xe1, 0x04, 0xa8, 0x02, 0x00, 0x00, 0xf1, 0x04, + 0x39, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0xd0, + 0x43, 0x8e, 0x01, 0x00, 0x00, 0xc7, 0x04, 0x95, + 0x01, 0x00, 0x00, 0x9e, 0x24, 0x01, 0x00, 0x0e, + 0xc8, 0x43, 0xa9, 0x02, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x0e, 0x0e, 0x29, 0xcd, 0x6d, 0x06, 0x00, + 0x00, 0x00, 0x0e, 0x29, 0x30, 0x29, 0x0c, 0x43, + 0x02, 0x01, 0xd2, 0x05, 0x00, 0x01, 0x00, 0x04, + 0x04, 0x00, 0x2f, 0x01, 0xf4, 0x05, 0x00, 0x00, + 0x00, 0xce, 0x03, 0x00, 0x0c, 0xce, 0x05, 0x89, + 0x01, 0x01, 0xf4, 0x03, 0x1c, 0x01, 0xf6, 0x03, + 0x1d, 0x01, 0x66, 0x00, 0x00, 0x43, 0xaa, 0x02, + 0x00, 0x00, 0xe0, 0x04, 0xa8, 0x02, 0x00, 0x00, + 0xf1, 0x24, 0x01, 0x00, 0xcf, 0xec, 0x1a, 0xc7, + 0x43, 0x4b, 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x43, 0x5e, 0x00, 0x00, 0x00, 0x04, 0x95, 0x01, + 0x00, 0x00, 0x24, 0x01, 0x00, 0xe9, 0xeb, 0xe6, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xd4, 0x05, 0x00, + 0x02, 0x00, 0x04, 0x04, 0x02, 0x51, 0x02, 0x9e, + 0x07, 0x00, 0x00, 0x00, 0xd8, 0x06, 0x00, 0x01, + 0x00, 0xce, 0x03, 0x00, 0x0c, 0xe4, 0x03, 0x14, + 0x01, 0xe2, 0x03, 0x13, 0x01, 0xea, 0x03, 0x17, + 0x01, 0x07, 0x16, 0x28, 0x5c, 0x64, 0x2b, 0x29, + 0x3b, 0x28, 0x5c, 0x64, 0x2b, 0x29, 0x07, 0xa8, + 0x01, 0x00, 0x00, 0x03, 0x00, 0x4c, 0x00, 0x00, + 0x00, 0x09, 0x06, 0x00, 0x00, 0x00, 0x05, 0x08, + 0xf5, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x0c, 0x01, + 0x1d, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x00, + 0x00, 0x16, 0x01, 0x00, 0x30, 0x00, 0x39, 0x00, + 0x0b, 0x0d, 0x01, 0x01, 0x3b, 0x0c, 0x02, 0x1d, + 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x00, 0x00, + 0x16, 0x01, 0x00, 0x30, 0x00, 0x39, 0x00, 0x0b, + 0x0d, 0x02, 0x0d, 0x00, 0x0b, 0x66, 0x00, 0x00, + 0x43, 0x9d, 0x02, 0x00, 0x00, 0x04, 0xab, 0x02, + 0x00, 0x00, 0x24, 0x01, 0x00, 0xd0, 0xec, 0x21, + 0xc8, 0x43, 0xbc, 0x01, 0x00, 0x00, 0xc0, 0x00, + 0xc0, 0x01, 0x34, 0x24, 0x01, 0x00, 0xcf, 0xec, + 0x10, 0xc7, 0xb8, 0x48, 0x8e, 0xb6, 0xb0, 0xec, + 0x08, 0xe1, 0x42, 0x61, 0x02, 0x00, 0x00, 0xe4, + 0x66, 0x00, 0x00, 0x43, 0x9d, 0x02, 0x00, 0x00, + 0x04, 0xac, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0xd0, 0xec, 0x0b, 0xc8, 0xb6, 0x48, 0x8e, 0xb6, + 0xb0, 0xec, 0x03, 0x09, 0xe6, 0x29, 0xc1, 0x00, + 0xc4, 0x35, 0xc1, 0x01, 0xc4, 0x36, 0xc1, 0x02, + 0xc4, 0x37, 0xc1, 0x03, 0xc4, 0x38, 0xc1, 0x04, + 0xc4, 0x39, 0xc1, 0x05, 0xc4, 0x3a, 0xc1, 0x06, + 0xc4, 0x3b, 0xc1, 0x07, 0xc4, 0x3c, 0xc1, 0x08, + 0xc4, 0x3d, 0xc1, 0x09, 0xc4, 0x3e, 0xc1, 0x0a, + 0xc4, 0x3f, 0xc1, 0x0b, 0xc4, 0x40, 0xc1, 0x0c, + 0xc4, 0x41, 0xc1, 0x0d, 0xc4, 0x42, 0xc1, 0x0e, + 0xc4, 0x43, 0xc1, 0x0f, 0xc4, 0x44, 0xc1, 0x10, + 0xc4, 0x45, 0xc1, 0x11, 0xc4, 0x46, 0xc1, 0x12, + 0xc4, 0x47, 0xc1, 0x13, 0xc4, 0x48, 0xc1, 0x14, + 0xc4, 0x49, 0xc1, 0x15, 0xc4, 0x4a, 0xc1, 0x16, + 0xc4, 0x4b, 0xc1, 0x17, 0xc4, 0x4c, 0xc1, 0x18, + 0xc4, 0x4d, 0xc1, 0x19, 0xc4, 0x4e, 0xc1, 0x1a, + 0xc4, 0x4f, 0xc1, 0x1b, 0xc4, 0x50, 0xc1, 0x1c, + 0xc4, 0x51, 0xc1, 0x1d, 0xc4, 0x52, 0xc1, 0x1e, + 0xc4, 0x53, 0xc1, 0x1f, 0xc4, 0x54, 0xc1, 0x20, + 0xc4, 0x55, 0xc1, 0x21, 0xc4, 0x56, 0xc1, 0x22, + 0xc4, 0x57, 0xc1, 0x23, 0xc4, 0x58, 0xc1, 0x24, + 0xc4, 0x59, 0xc1, 0x25, 0xc4, 0x5a, 0xc1, 0x26, + 0xc4, 0x5b, 0xc1, 0x27, 0xc4, 0x5c, 0xc1, 0x28, + 0xc4, 0x5d, 0xc1, 0x29, 0xc4, 0x5e, 0xc1, 0x2a, + 0xc4, 0x5f, 0xc1, 0x2b, 0xc4, 0x60, 0xc1, 0x2c, + 0xc4, 0x61, 0xc1, 0x2d, 0xc4, 0x62, 0xc1, 0x2e, + 0xc4, 0x63, 0xc1, 0x2f, 0xc4, 0x64, 0xc1, 0x30, + 0xc4, 0x65, 0xc1, 0x31, 0xc4, 0x66, 0xc1, 0x32, + 0xc4, 0x67, 0xc1, 0x33, 0xc4, 0x68, 0xc1, 0x34, + 0xc4, 0x69, 0xc1, 0x35, 0xc4, 0x6a, 0xc1, 0x36, + 0xc4, 0x6b, 0xc1, 0x37, 0xc4, 0x6c, 0xc1, 0x38, + 0xc4, 0x6e, 0xc1, 0x39, 0xc4, 0x72, 0xc1, 0x3a, + 0xc4, 0x73, 0xc1, 0x3b, 0xc4, 0x74, 0xc1, 0x3c, + 0xc4, 0x75, 0xc1, 0x3d, 0xc4, 0x76, 0xc1, 0x3e, + 0xc4, 0x77, 0xc1, 0x40, 0xc4, 0x79, 0xc1, 0x41, + 0xc4, 0x7a, 0xc1, 0x42, 0xc4, 0x7b, 0xc1, 0x43, + 0xc4, 0x7c, 0xc1, 0x44, 0xc4, 0x7d, 0xc1, 0x45, + 0xc4, 0x7e, 0xc1, 0x51, 0xc4, 0x80, 0xc1, 0x52, + 0xc4, 0x81, 0xc1, 0x53, 0xc4, 0x82, 0xc1, 0x54, + 0xc4, 0x83, 0xc1, 0x55, 0xc4, 0x84, 0xc1, 0x56, + 0xc4, 0x85, 0xc1, 0x57, 0xc4, 0x86, 0xc1, 0x58, + 0xc4, 0x87, 0xc1, 0x59, 0xc4, 0x88, 0xc1, 0x5a, + 0xc4, 0x89, 0xc1, 0x5b, 0xc4, 0x8a, 0xc1, 0x5c, + 0xc4, 0x8b, 0xc1, 0x5d, 0xc4, 0x8c, 0xd3, 0x66, + 0x02, 0x00, 0x44, 0xe9, 0x00, 0x00, 0x00, 0xd3, + 0x66, 0x01, 0x00, 0x44, 0xe8, 0x00, 0x00, 0x00, + 0xd3, 0x66, 0x00, 0x00, 0x44, 0xe7, 0x00, 0x00, + 0x00, 0xd3, 0x42, 0x94, 0x00, 0x00, 0x00, 0xcb, + 0xd3, 0x42, 0x98, 0x00, 0x00, 0x00, 0xcc, 0xd3, + 0x42, 0x97, 0x00, 0x00, 0x00, 0xcd, 0xd3, 0x42, + 0x99, 0x00, 0x00, 0x00, 0xce, 0xd3, 0x42, 0xb2, + 0x00, 0x00, 0x00, 0xc4, 0x04, 0xd3, 0x42, 0xa7, + 0x00, 0x00, 0x00, 0xc4, 0x05, 0xd3, 0x42, 0x95, + 0x00, 0x00, 0x00, 0xc4, 0x06, 0xd3, 0x42, 0x9e, + 0x00, 0x00, 0x00, 0xc4, 0x07, 0xd3, 0x42, 0xa2, + 0x00, 0x00, 0x00, 0xc4, 0x08, 0xd3, 0x42, 0x96, + 0x00, 0x00, 0x00, 0xc4, 0x09, 0xd3, 0x42, 0x9a, + 0x00, 0x00, 0x00, 0xc4, 0x0a, 0xd3, 0x42, 0x9c, + 0x00, 0x00, 0x00, 0xc4, 0x0b, 0xd3, 0x42, 0x9d, + 0x00, 0x00, 0x00, 0xc4, 0x0c, 0xd3, 0x42, 0xeb, + 0x00, 0x00, 0x00, 0xc4, 0x0d, 0xd3, 0x42, 0xec, + 0x00, 0x00, 0x00, 0xc4, 0x0e, 0xd3, 0x42, 0xed, + 0x00, 0x00, 0x00, 0xc4, 0x0f, 0xd3, 0x42, 0xee, + 0x00, 0x00, 0x00, 0xc4, 0x10, 0x04, 0xad, 0x02, + 0x00, 0x00, 0x04, 0xae, 0x02, 0x00, 0x00, 0x04, + 0xaf, 0x02, 0x00, 0x00, 0x04, 0xb0, 0x02, 0x00, + 0x00, 0x04, 0xb1, 0x02, 0x00, 0x00, 0x04, 0xb2, + 0x02, 0x00, 0x00, 0x04, 0xb3, 0x02, 0x00, 0x00, + 0x04, 0xb4, 0x02, 0x00, 0x00, 0x04, 0xb5, 0x02, + 0x00, 0x00, 0x04, 0xb6, 0x02, 0x00, 0x00, 0x04, + 0xb7, 0x02, 0x00, 0x00, 0x04, 0xb8, 0x02, 0x00, + 0x00, 0x04, 0xb9, 0x02, 0x00, 0x00, 0x04, 0x06, + 0x00, 0x00, 0x00, 0x04, 0xba, 0x02, 0x00, 0x00, + 0x04, 0x08, 0x00, 0x00, 0x00, 0x04, 0xbb, 0x02, + 0x00, 0x00, 0x04, 0xbc, 0x02, 0x00, 0x00, 0x04, + 0xbd, 0x02, 0x00, 0x00, 0x04, 0xbe, 0x02, 0x00, + 0x00, 0x04, 0xbf, 0x02, 0x00, 0x00, 0x26, 0x15, + 0x00, 0xc4, 0x11, 0x0b, 0x04, 0xc0, 0x02, 0x00, + 0x00, 0x4d, 0x8f, 0x01, 0x00, 0x00, 0x04, 0xc1, + 0x02, 0x00, 0x00, 0x4d, 0xc2, 0x02, 0x00, 0x00, + 0x04, 0xc3, 0x02, 0x00, 0x00, 0x4d, 0xc4, 0x02, + 0x00, 0x00, 0x04, 0xc5, 0x02, 0x00, 0x00, 0x4d, + 0xc6, 0x02, 0x00, 0x00, 0x04, 0xc7, 0x02, 0x00, + 0x00, 0x4d, 0xc8, 0x02, 0x00, 0x00, 0x04, 0xc9, + 0x02, 0x00, 0x00, 0x4d, 0xca, 0x02, 0x00, 0x00, + 0x04, 0xcb, 0x02, 0x00, 0x00, 0x4d, 0xcc, 0x02, + 0x00, 0x00, 0x04, 0xcd, 0x02, 0x00, 0x00, 0x4d, + 0xce, 0x02, 0x00, 0x00, 0x04, 0xcf, 0x02, 0x00, + 0x00, 0x4d, 0xd0, 0x02, 0x00, 0x00, 0x04, 0xd1, + 0x02, 0x00, 0x00, 0x4d, 0xd2, 0x02, 0x00, 0x00, + 0x04, 0xd1, 0x02, 0x00, 0x00, 0x4d, 0xd3, 0x02, + 0x00, 0x00, 0x04, 0xd4, 0x02, 0x00, 0x00, 0x4d, + 0xd5, 0x02, 0x00, 0x00, 0x04, 0xd6, 0x02, 0x00, + 0x00, 0x4d, 0xd7, 0x02, 0x00, 0x00, 0x04, 0xd8, + 0x02, 0x00, 0x00, 0x4d, 0xd9, 0x02, 0x00, 0x00, + 0x04, 0xda, 0x02, 0x00, 0x00, 0x4d, 0xdb, 0x02, + 0x00, 0x00, 0x04, 0xdc, 0x02, 0x00, 0x00, 0x4d, + 0xdd, 0x02, 0x00, 0x00, 0x04, 0xde, 0x02, 0x00, + 0x00, 0x4d, 0xdf, 0x02, 0x00, 0x00, 0x04, 0xe0, + 0x02, 0x00, 0x00, 0x4d, 0xe1, 0x02, 0x00, 0x00, + 0xc4, 0x12, 0x0b, 0x0b, 0x04, 0xce, 0x02, 0x00, + 0x00, 0x4d, 0x33, 0x02, 0x00, 0x00, 0x04, 0xe1, + 0x02, 0x00, 0x00, 0x4d, 0x48, 0x00, 0x00, 0x00, + 0x04, 0xd0, 0x02, 0x00, 0x00, 0x4d, 0x87, 0x02, + 0x00, 0x00, 0x04, 0xcc, 0x02, 0x00, 0x00, 0x4d, + 0x36, 0x02, 0x00, 0x00, 0x04, 0xd7, 0x02, 0x00, + 0x00, 0x4d, 0x16, 0x00, 0x00, 0x00, 0x04, 0xd5, + 0x02, 0x00, 0x00, 0x4d, 0x74, 0x02, 0x00, 0x00, + 0x04, 0xd9, 0x02, 0x00, 0x00, 0x4d, 0x1b, 0x00, + 0x00, 0x00, 0x04, 0xd7, 0x02, 0x00, 0x00, 0x4d, + 0x8b, 0x02, 0x00, 0x00, 0x04, 0xe1, 0x02, 0x00, + 0x00, 0x4d, 0x38, 0x02, 0x00, 0x00, 0x04, 0xe1, + 0x02, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0x00, + 0x04, 0xc6, 0x02, 0x00, 0x00, 0x4d, 0x47, 0x00, + 0x00, 0x00, 0x04, 0xd0, 0x02, 0x00, 0x00, 0x4d, + 0x35, 0x02, 0x00, 0x00, 0x04, 0xd0, 0x02, 0x00, + 0x00, 0x4d, 0x30, 0x02, 0x00, 0x00, 0x04, 0xce, + 0x02, 0x00, 0x00, 0x4d, 0x32, 0x02, 0x00, 0x00, + 0x04, 0xdf, 0x02, 0x00, 0x00, 0x4d, 0x49, 0x00, + 0x00, 0x00, 0x04, 0xe1, 0x02, 0x00, 0x00, 0x4d, + 0x4b, 0x00, 0x00, 0x00, 0x04, 0xdd, 0x02, 0x00, + 0x00, 0x4d, 0x09, 0x02, 0x00, 0x00, 0x04, 0xe1, + 0x02, 0x00, 0x00, 0x4d, 0x46, 0x00, 0x00, 0x00, + 0x4d, 0x5e, 0x02, 0x00, 0x00, 0x0b, 0x04, 0xce, + 0x02, 0x00, 0x00, 0x4d, 0x33, 0x02, 0x00, 0x00, + 0x04, 0xdd, 0x02, 0x00, 0x00, 0x4d, 0x48, 0x00, + 0x00, 0x00, 0x04, 0xd3, 0x02, 0x00, 0x00, 0x4d, + 0x87, 0x02, 0x00, 0x00, 0x04, 0xcc, 0x02, 0x00, + 0x00, 0x4d, 0x36, 0x02, 0x00, 0x00, 0x04, 0xc2, + 0x02, 0x00, 0x00, 0x4d, 0x16, 0x00, 0x00, 0x00, + 0x04, 0xc4, 0x02, 0x00, 0x00, 0x4d, 0x74, 0x02, + 0x00, 0x00, 0x04, 0xd9, 0x02, 0x00, 0x00, 0x4d, + 0x1b, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x02, 0x00, + 0x00, 0x4d, 0x8b, 0x02, 0x00, 0x00, 0x04, 0xdd, + 0x02, 0x00, 0x00, 0x4d, 0x38, 0x02, 0x00, 0x00, + 0x04, 0xdd, 0x02, 0x00, 0x00, 0x4d, 0x01, 0x00, + 0x00, 0x00, 0x04, 0xc6, 0x02, 0x00, 0x00, 0x4d, + 0x47, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x02, 0x00, + 0x00, 0x4d, 0x35, 0x02, 0x00, 0x00, 0x04, 0xc2, + 0x02, 0x00, 0x00, 0x4d, 0x30, 0x02, 0x00, 0x00, + 0x04, 0xce, 0x02, 0x00, 0x00, 0x4d, 0x32, 0x02, + 0x00, 0x00, 0x04, 0xdf, 0x02, 0x00, 0x00, 0x4d, + 0x49, 0x00, 0x00, 0x00, 0x04, 0xd3, 0x02, 0x00, + 0x00, 0x4d, 0x4b, 0x00, 0x00, 0x00, 0x04, 0xdd, + 0x02, 0x00, 0x00, 0x4d, 0x09, 0x02, 0x00, 0x00, + 0x04, 0xdd, 0x02, 0x00, 0x00, 0x4d, 0x46, 0x00, + 0x00, 0x00, 0x4d, 0x61, 0x02, 0x00, 0x00, 0xc5, + 0x13, 0x42, 0x5e, 0x02, 0x00, 0x00, 0xc4, 0x14, + 0x0a, 0xc4, 0x15, 0x09, 0xc4, 0x16, 0x0a, 0xc4, + 0x17, 0x09, 0xc4, 0x18, 0xb8, 0xc4, 0x19, 0x09, + 0xc4, 0x1a, 0x09, 0xc4, 0x1b, 0x26, 0x00, 0x00, + 0xc4, 0x1c, 0xc2, 0xc4, 0x1e, 0xc2, 0xc4, 0x1f, + 0xc2, 0xc4, 0x20, 0xb6, 0xc4, 0x21, 0x04, 0xe2, + 0x02, 0x00, 0x00, 0xc4, 0x22, 0x04, 0xe3, 0x02, + 0x00, 0x00, 0xc4, 0x23, 0xb6, 0xc4, 0x25, 0xc2, + 0xc4, 0x26, 0xb6, 0xc4, 0x27, 0xc2, 0xc4, 0x28, + 0xb6, 0xc4, 0x29, 0xc2, 0xc4, 0x2a, 0xb6, 0xc4, + 0x2b, 0x09, 0xc4, 0x2e, 0xb6, 0xc4, 0x2f, 0xb6, + 0xc4, 0x30, 0xb6, 0xc4, 0x34, 0x0b, 0xc3, 0x48, + 0x4d, 0xe4, 0x02, 0x00, 0x00, 0xc3, 0x4b, 0x4d, + 0xe5, 0x02, 0x00, 0x00, 0xc3, 0x66, 0x4d, 0xe6, + 0x02, 0x00, 0x00, 0xc3, 0x5a, 0x4d, 0xe7, 0x02, + 0x00, 0x00, 0xc3, 0x49, 0x4d, 0xe8, 0x02, 0x00, + 0x00, 0xc3, 0x4a, 0x4d, 0xe9, 0x02, 0x00, 0x00, + 0xc3, 0x46, 0x4d, 0xea, 0x02, 0x00, 0x00, 0xc3, + 0x5b, 0x4d, 0xeb, 0x02, 0x00, 0x00, 0xc3, 0x6c, + 0x4d, 0x98, 0x02, 0x00, 0x00, 0xc3, 0x51, 0x4d, + 0x95, 0x01, 0x00, 0x00, 0xc3, 0x61, 0x4d, 0xec, + 0x02, 0x00, 0x00, 0xc3, 0x50, 0x4d, 0xed, 0x02, + 0x00, 0x00, 0xc3, 0x51, 0x4d, 0x99, 0x02, 0x00, + 0x00, 0xc3, 0x54, 0x4d, 0xee, 0x02, 0x00, 0x00, + 0xc3, 0x53, 0x4d, 0xef, 0x02, 0x00, 0x00, 0xc3, + 0x45, 0x4d, 0xf0, 0x02, 0x00, 0x00, 0xc3, 0x47, + 0x4d, 0xf1, 0x02, 0x00, 0x00, 0xc3, 0x47, 0x4d, + 0xf2, 0x02, 0x00, 0x00, 0xc3, 0x5c, 0x4d, 0xf3, + 0x02, 0x00, 0x00, 0xc3, 0x64, 0x4d, 0xf4, 0x02, + 0x00, 0x00, 0xc3, 0x67, 0x4d, 0xf5, 0x02, 0x00, + 0x00, 0xc3, 0x65, 0x4d, 0xf6, 0x02, 0x00, 0x00, + 0xc3, 0x53, 0x4d, 0xf7, 0x02, 0x00, 0x00, 0xc3, + 0x54, 0x4d, 0xf8, 0x02, 0x00, 0x00, 0xc3, 0x4a, + 0x4d, 0xf9, 0x02, 0x00, 0x00, 0xc3, 0x4b, 0x4d, + 0xfa, 0x02, 0x00, 0x00, 0xc3, 0x4e, 0x4d, 0xfb, + 0x02, 0x00, 0x00, 0xc3, 0x4f, 0x4d, 0xfc, 0x02, + 0x00, 0x00, 0xc3, 0x4e, 0x4d, 0xfd, 0x02, 0x00, + 0x00, 0xc3, 0x4f, 0x4d, 0xfe, 0x02, 0x00, 0x00, + 0xc3, 0x48, 0x4d, 0xff, 0x02, 0x00, 0x00, 0xc3, + 0x59, 0x4d, 0x00, 0x03, 0x00, 0x00, 0xc3, 0x49, + 0x4d, 0x01, 0x03, 0x00, 0x00, 0xc3, 0x56, 0x4d, + 0x02, 0x03, 0x00, 0x00, 0xc3, 0x57, 0x4d, 0x03, + 0x03, 0x00, 0x00, 0xc3, 0x53, 0x4d, 0x04, 0x03, + 0x00, 0x00, 0xc3, 0x54, 0x4d, 0x05, 0x03, 0x00, + 0x00, 0xc3, 0x4a, 0x4d, 0x06, 0x03, 0x00, 0x00, + 0xc3, 0x4b, 0x4d, 0x07, 0x03, 0x00, 0x00, 0xc3, + 0x49, 0x4d, 0x08, 0x03, 0x00, 0x00, 0xc3, 0x48, + 0x4d, 0x09, 0x03, 0x00, 0x00, 0xc3, 0x64, 0x4d, + 0x0a, 0x03, 0x00, 0x00, 0xc3, 0x4f, 0x4d, 0x0b, + 0x03, 0x00, 0x00, 0xc3, 0x63, 0x4d, 0x0c, 0x03, + 0x00, 0x00, 0xc3, 0x4e, 0x4d, 0x0d, 0x03, 0x00, + 0x00, 0xc3, 0x62, 0x4d, 0x0e, 0x03, 0x00, 0x00, + 0xc3, 0x5f, 0x4d, 0x0f, 0x03, 0x00, 0x00, 0xc3, + 0x5d, 0x4d, 0x10, 0x03, 0x00, 0x00, 0xc3, 0x5e, + 0x4d, 0x11, 0x03, 0x00, 0x00, 0xc3, 0x5b, 0x4d, + 0x12, 0x03, 0x00, 0x00, 0xc4, 0x6d, 0x0b, 0xc5, + 0x78, 0xc1, 0x3f, 0x44, 0x47, 0x02, 0x00, 0x00, + 0xc7, 0x43, 0x61, 0x00, 0x00, 0x00, 0x0b, 0xc3, + 0x7b, 0x4d, 0x59, 0x01, 0x00, 0x00, 0xc3, 0x7c, + 0x4d, 0x5a, 0x01, 0x00, 0x00, 0xc1, 0x46, 0x4e, + 0x13, 0x03, 0x00, 0x00, 0x4d, 0x13, 0x03, 0x00, + 0x00, 0xc1, 0x47, 0x4e, 0x14, 0x03, 0x00, 0x00, + 0x4d, 0x14, 0x03, 0x00, 0x00, 0xc1, 0x48, 0x4e, + 0x15, 0x03, 0x00, 0x00, 0x4d, 0x15, 0x03, 0x00, + 0x00, 0xc1, 0x49, 0x4e, 0x16, 0x03, 0x00, 0x00, + 0x4d, 0x16, 0x03, 0x00, 0x00, 0xc1, 0x4a, 0x4e, + 0x46, 0x02, 0x00, 0x00, 0x4d, 0x46, 0x02, 0x00, + 0x00, 0xc1, 0x4b, 0x4e, 0x17, 0x03, 0x00, 0x00, + 0x4d, 0x17, 0x03, 0x00, 0x00, 0xc1, 0x4c, 0x4e, + 0x2f, 0x02, 0x00, 0x00, 0x4d, 0x2f, 0x02, 0x00, + 0x00, 0xc1, 0x4d, 0x4e, 0x5e, 0x02, 0x00, 0x00, + 0x4d, 0x5e, 0x02, 0x00, 0x00, 0xc1, 0x4e, 0x4e, + 0x61, 0x02, 0x00, 0x00, 0x4d, 0x61, 0x02, 0x00, + 0x00, 0xc1, 0x4f, 0x4e, 0xa1, 0x01, 0x00, 0x00, + 0x4d, 0xa1, 0x01, 0x00, 0x00, 0xc1, 0x50, 0x4e, + 0x18, 0x03, 0x00, 0x00, 0x4d, 0x18, 0x03, 0x00, + 0x00, 0x07, 0x24, 0x02, 0x00, 0xc4, 0x7f, 0xc3, + 0x8c, 0xf0, 0x0e, 0xc3, 0x8b, 0xf0, 0x0e, 0xc3, + 0x35, 0xf0, 0x0e, 0xc3, 0x80, 0xf0, 0x29, 0x08, + 0xec, 0x02, 0x29, 0xc1, 0x00, 0x39, 0x8d, 0x00, + 0x00, 0x00, 0xf1, 0x0e, 0x06, 0x2f, +}; + diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/gen/standalone.c b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/standalone.c new file mode 100644 index 0000000..53aacca --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/standalone.c @@ -0,0 +1,323 @@ +/* File generated automatically by the QuickJS-ng compiler. */ + +#include + +const uint32_t qjsc_standalone_size = 2511; + +const uint8_t qjsc_standalone[2511] = { + 0x15, 0x4e, 0x01, 0x1a, 0x73, 0x74, 0x61, 0x6e, + 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x2e, 0x6a, + 0x73, 0x01, 0x0e, 0x71, 0x6a, 0x73, 0x3a, 0x73, + 0x74, 0x64, 0x01, 0x0c, 0x71, 0x6a, 0x73, 0x3a, + 0x6f, 0x73, 0x01, 0x12, 0x71, 0x6a, 0x73, 0x3a, + 0x62, 0x6a, 0x73, 0x6f, 0x6e, 0x01, 0x22, 0x63, + 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x53, 0x74, + 0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, + 0x01, 0x1a, 0x72, 0x75, 0x6e, 0x53, 0x74, 0x61, + 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x01, + 0x06, 0x73, 0x74, 0x64, 0x01, 0x04, 0x6f, 0x73, + 0x01, 0x0a, 0x62, 0x6a, 0x73, 0x6f, 0x6e, 0x01, + 0x28, 0x4a, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, + 0x5f, 0x4f, 0x42, 0x4a, 0x5f, 0x42, 0x59, 0x54, + 0x45, 0x43, 0x4f, 0x44, 0x45, 0x01, 0x2a, 0x4a, + 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x4f, + 0x42, 0x4a, 0x5f, 0x52, 0x45, 0x46, 0x45, 0x52, + 0x45, 0x4e, 0x43, 0x45, 0x01, 0x2a, 0x4a, 0x53, + 0x5f, 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x4f, + 0x42, 0x4a, 0x5f, 0x42, 0x59, 0x54, 0x45, 0x43, + 0x4f, 0x44, 0x45, 0x01, 0x2c, 0x4a, 0x53, 0x5f, + 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x4f, 0x42, + 0x4a, 0x5f, 0x52, 0x45, 0x46, 0x45, 0x52, 0x45, + 0x4e, 0x43, 0x45, 0x01, 0x32, 0x4a, 0x53, 0x5f, + 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x4f, 0x42, + 0x4a, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x50, 0x5f, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x01, 0x0e, + 0x54, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x01, + 0x16, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x41, + 0x73, 0x63, 0x69, 0x69, 0x01, 0x16, 0x64, 0x65, + 0x63, 0x6f, 0x64, 0x65, 0x41, 0x73, 0x63, 0x69, + 0x69, 0x01, 0x06, 0x74, 0x78, 0x74, 0x01, 0x02, + 0x63, 0x01, 0x14, 0x63, 0x68, 0x61, 0x72, 0x43, + 0x6f, 0x64, 0x65, 0x41, 0x74, 0x01, 0x06, 0x6d, + 0x61, 0x70, 0x01, 0x06, 0x62, 0x75, 0x66, 0x01, + 0x18, 0x66, 0x72, 0x6f, 0x6d, 0x43, 0x68, 0x61, + 0x72, 0x43, 0x6f, 0x64, 0x65, 0x01, 0x0c, 0x69, + 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x0e, 0x6f, + 0x75, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x12, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x45, 0x78, + 0x65, 0x01, 0x04, 0x6a, 0x73, 0x01, 0x08, 0x63, + 0x6f, 0x64, 0x65, 0x01, 0x10, 0x62, 0x79, 0x74, + 0x65, 0x63, 0x6f, 0x64, 0x65, 0x01, 0x16, 0x65, + 0x78, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x01, 0x06, 0x65, 0x78, 0x65, 0x01, + 0x0e, 0x65, 0x78, 0x65, 0x53, 0x69, 0x7a, 0x65, + 0x01, 0x12, 0x6e, 0x65, 0x77, 0x42, 0x75, 0x66, + 0x66, 0x65, 0x72, 0x01, 0x0c, 0x6e, 0x65, 0x77, + 0x45, 0x78, 0x65, 0x01, 0x04, 0x64, 0x77, 0x01, + 0x0a, 0x6e, 0x65, 0x77, 0x46, 0x64, 0x01, 0x10, + 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, + 0x01, 0x1e, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, + 0x20, 0x74, 0x6f, 0x20, 0x6f, 0x70, 0x65, 0x6e, + 0x20, 0x01, 0x14, 0x65, 0x76, 0x61, 0x6c, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x01, 0x18, 0x63, + 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x5f, 0x6f, + 0x6e, 0x6c, 0x79, 0x01, 0x1c, 0x63, 0x6f, 0x6d, + 0x70, 0x69, 0x6c, 0x65, 0x5f, 0x6d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x01, 0x0a, 0x77, 0x72, 0x69, + 0x74, 0x65, 0x01, 0x0e, 0x65, 0x78, 0x65, 0x50, + 0x61, 0x74, 0x68, 0x01, 0x0a, 0x61, 0x72, 0x67, + 0x76, 0x30, 0x01, 0x0c, 0x62, 0x69, 0x6e, 0x61, + 0x72, 0x79, 0x01, 0x36, 0x66, 0x61, 0x69, 0x6c, + 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6f, 0x70, + 0x65, 0x6e, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x20, 0x01, + 0x0c, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x01, + 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, + 0x72, 0x01, 0x08, 0x53, 0x69, 0x7a, 0x65, 0x01, + 0x0a, 0x4d, 0x61, 0x67, 0x69, 0x63, 0x01, 0x12, + 0x4d, 0x61, 0x67, 0x69, 0x63, 0x53, 0x69, 0x7a, + 0x65, 0x01, 0x10, 0x44, 0x61, 0x74, 0x61, 0x53, + 0x69, 0x7a, 0x65, 0x01, 0x12, 0x73, 0x65, 0x74, + 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x01, 0x08, + 0x6f, 0x70, 0x65, 0x6e, 0x01, 0x10, 0x4f, 0x5f, + 0x57, 0x52, 0x4f, 0x4e, 0x4c, 0x59, 0x01, 0x0e, + 0x4f, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x01, + 0x0e, 0x4f, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x43, + 0x01, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, + 0x20, 0x74, 0x6f, 0x20, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x20, 0x01, 0x14, 0x62, 0x79, 0x74, + 0x65, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x01, + 0x0a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x01, 0x3c, + 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x74, + 0x6f, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x01, 0x08, + 0x66, 0x69, 0x6c, 0x65, 0x01, 0x02, 0x72, 0x01, + 0x0e, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, + 0x01, 0x0a, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x01, + 0x0c, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x01, + 0x04, 0x72, 0x62, 0x01, 0x08, 0x73, 0x65, 0x65, + 0x6b, 0x01, 0x10, 0x53, 0x45, 0x45, 0x4b, 0x5f, + 0x45, 0x4e, 0x44, 0x01, 0x18, 0x73, 0x65, 0x65, + 0x6b, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x3a, + 0x20, 0x01, 0x08, 0x72, 0x65, 0x61, 0x64, 0x01, + 0x40, 0x63, 0x6f, 0x72, 0x72, 0x75, 0x70, 0x74, + 0x65, 0x64, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, + 0x79, 0x2c, 0x20, 0x6d, 0x61, 0x67, 0x69, 0x63, + 0x20, 0x6d, 0x69, 0x73, 0x6d, 0x61, 0x74, 0x63, + 0x68, 0x01, 0x12, 0x67, 0x65, 0x74, 0x55, 0x69, + 0x6e, 0x74, 0x33, 0x32, 0x01, 0x10, 0x53, 0x45, + 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x01, 0x0a, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x01, 0x14, 0x72, + 0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x01, 0x16, 0x65, 0x76, 0x61, 0x6c, 0x5f, + 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x01, 0x10, + 0x71, 0x75, 0x69, 0x63, 0x6b, 0x6a, 0x73, 0x32, + 0x0d, 0xc6, 0x03, 0x03, 0xc8, 0x03, 0xca, 0x03, + 0xcc, 0x03, 0x02, 0x00, 0x0b, 0xce, 0x03, 0x00, + 0x0c, 0xd0, 0x03, 0x00, 0x03, 0x00, 0xfe, 0x01, + 0x00, 0x01, 0xfe, 0x01, 0x01, 0x02, 0xfe, 0x01, + 0x02, 0x00, 0x0c, 0x20, 0x02, 0x01, 0xa2, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x0d, 0x04, 0x58, 0x00, + 0xd2, 0x03, 0x00, 0x0d, 0xd4, 0x03, 0x01, 0x0d, + 0xd6, 0x03, 0x02, 0x0d, 0xd8, 0x03, 0x00, 0x0d, + 0xda, 0x03, 0x01, 0x0d, 0xdc, 0x03, 0x02, 0x0d, + 0xde, 0x03, 0x03, 0x0d, 0xe0, 0x03, 0x04, 0x0d, + 0xe2, 0x03, 0x05, 0x0d, 0xe4, 0x03, 0x06, 0x01, + 0xe6, 0x03, 0x07, 0x01, 0xce, 0x03, 0x08, 0x01, + 0xd0, 0x03, 0x09, 0x01, 0x0c, 0x43, 0x02, 0x01, + 0xe4, 0x03, 0x01, 0x00, 0x01, 0x05, 0x00, 0x01, + 0x1e, 0x01, 0xe8, 0x03, 0x00, 0x01, 0x00, 0x0c, + 0x42, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, + 0x00, 0x00, 0x0a, 0x01, 0xea, 0x03, 0x00, 0x01, + 0x00, 0xd3, 0x43, 0xf6, 0x00, 0x00, 0x00, 0xb6, + 0x25, 0x01, 0x00, 0x39, 0xa7, 0x00, 0x00, 0x00, + 0x11, 0xd3, 0x43, 0x5e, 0x00, 0x00, 0x00, 0xc2, + 0x24, 0x01, 0x00, 0x43, 0xf7, 0x00, 0x00, 0x00, + 0xc1, 0x00, 0x24, 0x01, 0x00, 0x21, 0x01, 0x00, + 0x28, 0x0c, 0x43, 0x02, 0x01, 0xe6, 0x03, 0x01, + 0x00, 0x01, 0x03, 0x00, 0x01, 0x21, 0x01, 0xf0, + 0x03, 0x00, 0x01, 0x00, 0x0c, 0x42, 0x02, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x03, 0x00, 0x00, 0x0e, + 0x01, 0xea, 0x03, 0x00, 0x01, 0x00, 0x39, 0x98, + 0x00, 0x00, 0x00, 0x43, 0xf9, 0x00, 0x00, 0x00, + 0xd3, 0x25, 0x01, 0x00, 0x39, 0x95, 0x00, 0x00, + 0x00, 0x43, 0x7b, 0x00, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0x43, 0xf7, 0x00, 0x00, 0x00, 0xc1, + 0x00, 0x24, 0x01, 0x00, 0x43, 0x5c, 0x00, 0x00, + 0x00, 0xc2, 0x25, 0x01, 0x00, 0x0c, 0x43, 0x02, + 0x01, 0xce, 0x03, 0x03, 0x0a, 0x03, 0x07, 0x08, + 0x00, 0x96, 0x04, 0x0d, 0xf4, 0x03, 0x00, 0x01, + 0x00, 0xf6, 0x03, 0x00, 0x01, 0x00, 0xf8, 0x03, + 0x00, 0x01, 0x00, 0xfa, 0x03, 0x01, 0x00, 0x30, + 0xfc, 0x03, 0x01, 0x01, 0x30, 0xfe, 0x03, 0x01, + 0x02, 0x30, 0x80, 0x04, 0x01, 0x03, 0x30, 0x82, + 0x04, 0x01, 0x04, 0x30, 0x84, 0x04, 0x01, 0x05, + 0x30, 0x86, 0x04, 0x01, 0x06, 0x30, 0x88, 0x04, + 0x01, 0x07, 0x30, 0x8a, 0x04, 0x01, 0x08, 0x30, + 0x8c, 0x04, 0x01, 0x09, 0x30, 0xd2, 0x03, 0x00, + 0x0c, 0xd6, 0x03, 0x02, 0x0c, 0xdc, 0x03, 0x05, + 0x0c, 0xde, 0x03, 0x06, 0x0c, 0xe0, 0x03, 0x07, + 0x0c, 0xd4, 0x03, 0x01, 0x0c, 0xe2, 0x03, 0x08, + 0x0c, 0xe4, 0x03, 0x09, 0x00, 0x62, 0x09, 0x00, + 0x62, 0x08, 0x00, 0x62, 0x07, 0x00, 0x62, 0x06, + 0x00, 0x62, 0x05, 0x00, 0x62, 0x04, 0x00, 0x62, + 0x03, 0x00, 0x62, 0x02, 0x00, 0x62, 0x01, 0x00, + 0x62, 0x00, 0x00, 0x66, 0x00, 0x00, 0x43, 0x07, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xcb, + 0x63, 0x00, 0x00, 0x97, 0xec, 0x19, 0x39, 0x96, + 0x00, 0x00, 0x00, 0x11, 0x04, 0x08, 0x01, 0x00, + 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0x21, 0x01, 0x00, 0x30, 0x66, 0x00, + 0x00, 0x43, 0x09, 0x01, 0x00, 0x00, 0x63, 0x00, + 0x00, 0x0b, 0x0a, 0x4d, 0x0a, 0x01, 0x00, 0x00, + 0x0a, 0x4d, 0x0b, 0x01, 0x00, 0x00, 0x24, 0x02, + 0x00, 0xcc, 0x39, 0xa7, 0x00, 0x00, 0x00, 0x11, + 0x66, 0x01, 0x00, 0x43, 0x0c, 0x01, 0x00, 0x00, + 0x63, 0x01, 0x00, 0x66, 0x02, 0x00, 0x66, 0x03, + 0x00, 0xa5, 0x66, 0x04, 0x00, 0xa5, 0x24, 0x02, + 0x00, 0x21, 0x01, 0x00, 0xcd, 0xd5, 0x11, 0xb1, + 0xec, 0x1c, 0x0e, 0x66, 0x05, 0x00, 0x43, 0x0d, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x11, 0xb1, + 0xec, 0x0c, 0x0e, 0x39, 0x8d, 0x00, 0x00, 0x00, + 0x42, 0x0e, 0x01, 0x00, 0x00, 0xce, 0x66, 0x00, + 0x00, 0x43, 0x07, 0x01, 0x00, 0x00, 0x63, 0x03, + 0x00, 0x0b, 0x0a, 0x4d, 0x0f, 0x01, 0x00, 0x00, + 0x24, 0x02, 0x00, 0xc4, 0x04, 0x63, 0x04, 0x00, + 0x97, 0xec, 0x1b, 0x39, 0x96, 0x00, 0x00, 0x00, + 0x11, 0x04, 0x10, 0x01, 0x00, 0x00, 0x43, 0x5d, + 0x00, 0x00, 0x00, 0x63, 0x03, 0x00, 0x24, 0x01, + 0x00, 0x21, 0x01, 0x00, 0x30, 0x63, 0x04, 0x00, + 0xeb, 0xc4, 0x05, 0x63, 0x04, 0x00, 0x42, 0x11, + 0x01, 0x00, 0x00, 0x43, 0x12, 0x01, 0x00, 0x00, + 0x63, 0x05, 0x00, 0x63, 0x02, 0x00, 0xeb, 0x9e, + 0x66, 0x06, 0x00, 0x42, 0x13, 0x01, 0x00, 0x00, + 0x9e, 0x24, 0x01, 0x00, 0xc4, 0x06, 0x39, 0xa7, + 0x00, 0x00, 0x00, 0x11, 0x63, 0x06, 0x00, 0x21, + 0x01, 0x00, 0xc4, 0x07, 0x63, 0x07, 0x00, 0x43, + 0x43, 0x00, 0x00, 0x00, 0x63, 0x02, 0x00, 0x63, + 0x05, 0x00, 0x24, 0x02, 0x00, 0x0e, 0x63, 0x07, + 0x00, 0x43, 0x43, 0x00, 0x00, 0x00, 0x5f, 0x07, + 0x00, 0x66, 0x06, 0x00, 0x42, 0x14, 0x01, 0x00, + 0x00, 0xf1, 0x63, 0x05, 0x00, 0x63, 0x02, 0x00, + 0xeb, 0x9e, 0x24, 0x02, 0x00, 0x0e, 0x39, 0xb1, + 0x00, 0x00, 0x00, 0x11, 0x63, 0x06, 0x00, 0x63, + 0x05, 0x00, 0x63, 0x02, 0x00, 0xeb, 0x9e, 0x66, + 0x06, 0x00, 0x42, 0x15, 0x01, 0x00, 0x00, 0x9e, + 0x66, 0x06, 0x00, 0x42, 0x16, 0x01, 0x00, 0x00, + 0x21, 0x03, 0x00, 0xc4, 0x08, 0x63, 0x08, 0x00, + 0x43, 0x17, 0x01, 0x00, 0x00, 0xb6, 0x63, 0x05, + 0x00, 0x0a, 0x24, 0x03, 0x00, 0x0e, 0x66, 0x05, + 0x00, 0x43, 0x18, 0x01, 0x00, 0x00, 0xd4, 0x66, + 0x05, 0x00, 0x42, 0x19, 0x01, 0x00, 0x00, 0x66, + 0x05, 0x00, 0x42, 0x1a, 0x01, 0x00, 0x00, 0xa5, + 0x66, 0x05, 0x00, 0x42, 0x1b, 0x01, 0x00, 0x00, + 0xa5, 0xbf, 0xed, 0x01, 0x24, 0x03, 0x00, 0xc4, + 0x09, 0x63, 0x09, 0x00, 0xb6, 0xa7, 0xec, 0x19, + 0x39, 0x96, 0x00, 0x00, 0x00, 0x11, 0x04, 0x1c, + 0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, + 0xd4, 0x24, 0x01, 0x00, 0x21, 0x01, 0x00, 0x30, + 0x66, 0x05, 0x00, 0x43, 0x0c, 0x01, 0x00, 0x00, + 0x63, 0x09, 0x00, 0x63, 0x06, 0x00, 0xb6, 0x63, + 0x06, 0x00, 0x42, 0x1d, 0x01, 0x00, 0x00, 0x24, + 0x04, 0x00, 0xb6, 0xa7, 0xec, 0x1f, 0x66, 0x05, + 0x00, 0x43, 0x1e, 0x01, 0x00, 0x00, 0x63, 0x09, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0x39, 0x96, 0x00, + 0x00, 0x00, 0x11, 0x04, 0x1f, 0x01, 0x00, 0x00, + 0x21, 0x01, 0x00, 0x30, 0x66, 0x05, 0x00, 0x43, + 0x1e, 0x01, 0x00, 0x00, 0x63, 0x09, 0x00, 0x24, + 0x01, 0x00, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xd0, + 0x03, 0x00, 0x09, 0x00, 0x07, 0x07, 0x00, 0xb4, + 0x04, 0x09, 0xc0, 0x04, 0x01, 0x00, 0x30, 0x82, + 0x04, 0x01, 0x01, 0x30, 0xc2, 0x04, 0x01, 0x02, + 0x20, 0xc4, 0x04, 0x01, 0x03, 0x30, 0xc6, 0x04, + 0x01, 0x04, 0x30, 0x8a, 0x04, 0x01, 0x05, 0x30, + 0xc8, 0x04, 0x01, 0x06, 0x30, 0xfe, 0x03, 0x01, + 0x07, 0x30, 0xfc, 0x03, 0x01, 0x08, 0x30, 0xd4, + 0x03, 0x01, 0x0c, 0xd2, 0x03, 0x00, 0x0c, 0xe2, + 0x03, 0x08, 0x0c, 0xe6, 0x03, 0x0a, 0x00, 0xd6, + 0x03, 0x02, 0x0c, 0xd8, 0x03, 0x03, 0x0c, 0xda, + 0x03, 0x04, 0x0c, 0x62, 0x08, 0x00, 0x62, 0x07, + 0x00, 0x62, 0x06, 0x00, 0x62, 0x05, 0x00, 0x62, + 0x04, 0x00, 0x62, 0x03, 0x00, 0x62, 0x02, 0x00, + 0x62, 0x01, 0x00, 0x62, 0x00, 0x00, 0x66, 0x00, + 0x00, 0x43, 0x0d, 0x01, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x11, 0xb1, 0xec, 0x0c, 0x0e, 0x39, 0x8d, + 0x00, 0x00, 0x00, 0x42, 0x0e, 0x01, 0x00, 0x00, + 0xcb, 0x66, 0x01, 0x00, 0x43, 0x18, 0x01, 0x00, + 0x00, 0x63, 0x00, 0x00, 0x04, 0x25, 0x01, 0x00, + 0x00, 0x24, 0x02, 0x00, 0xcc, 0x63, 0x01, 0x00, + 0x97, 0xec, 0x1b, 0x39, 0x96, 0x00, 0x00, 0x00, + 0x11, 0x04, 0x10, 0x01, 0x00, 0x00, 0x43, 0x5d, + 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x21, 0x01, 0x00, 0x30, 0x63, 0x01, 0x00, + 0x43, 0x26, 0x01, 0x00, 0x00, 0x66, 0x02, 0x00, + 0x42, 0x13, 0x01, 0x00, 0x00, 0x8d, 0x66, 0x01, + 0x00, 0x42, 0x27, 0x01, 0x00, 0x00, 0x24, 0x02, + 0x00, 0xcd, 0x63, 0x02, 0x00, 0xb6, 0xa7, 0xec, + 0x1c, 0x39, 0x96, 0x00, 0x00, 0x00, 0x11, 0x04, + 0x28, 0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, + 0x00, 0x63, 0x02, 0x00, 0x8d, 0x24, 0x01, 0x00, + 0x21, 0x01, 0x00, 0x30, 0x39, 0xa7, 0x00, 0x00, + 0x00, 0x11, 0x66, 0x02, 0x00, 0x42, 0x13, 0x01, + 0x00, 0x00, 0x21, 0x01, 0x00, 0xce, 0x63, 0x01, + 0x00, 0x43, 0x29, 0x01, 0x00, 0x00, 0x63, 0x03, + 0x00, 0x42, 0x11, 0x01, 0x00, 0x00, 0xb6, 0x66, + 0x02, 0x00, 0x42, 0x13, 0x01, 0x00, 0x00, 0x24, + 0x03, 0x00, 0x0e, 0x39, 0xa7, 0x00, 0x00, 0x00, + 0x11, 0x63, 0x03, 0x00, 0x42, 0x11, 0x01, 0x00, + 0x00, 0xb6, 0x66, 0x02, 0x00, 0x42, 0x15, 0x01, + 0x00, 0x00, 0x21, 0x03, 0x00, 0xc4, 0x04, 0xe2, + 0x63, 0x04, 0x00, 0xf1, 0x66, 0x02, 0x00, 0x42, + 0x14, 0x01, 0x00, 0x00, 0xb0, 0xec, 0x1c, 0x63, + 0x01, 0x00, 0x43, 0x1e, 0x01, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x0e, 0x39, 0x96, 0x00, 0x00, 0x00, + 0x11, 0x04, 0x2a, 0x01, 0x00, 0x00, 0x21, 0x01, + 0x00, 0x30, 0x39, 0xb1, 0x00, 0x00, 0x00, 0x11, + 0x63, 0x03, 0x00, 0x42, 0x11, 0x01, 0x00, 0x00, + 0x66, 0x02, 0x00, 0x42, 0x15, 0x01, 0x00, 0x00, + 0x66, 0x02, 0x00, 0x42, 0x16, 0x01, 0x00, 0x00, + 0x21, 0x03, 0x00, 0xc4, 0x05, 0x63, 0x05, 0x00, + 0x43, 0x2b, 0x01, 0x00, 0x00, 0xb6, 0x0a, 0x24, + 0x02, 0x00, 0xc4, 0x06, 0x39, 0xa7, 0x00, 0x00, + 0x00, 0x11, 0x63, 0x06, 0x00, 0x66, 0x02, 0x00, + 0x42, 0x13, 0x01, 0x00, 0x00, 0x9f, 0x21, 0x01, + 0x00, 0xc4, 0x07, 0x63, 0x01, 0x00, 0x43, 0x26, + 0x01, 0x00, 0x00, 0x63, 0x06, 0x00, 0x66, 0x01, + 0x00, 0x42, 0x2c, 0x01, 0x00, 0x00, 0x24, 0x02, + 0x00, 0x11, 0x64, 0x02, 0x00, 0x0e, 0x63, 0x02, + 0x00, 0xb6, 0xa7, 0xec, 0x28, 0x63, 0x01, 0x00, + 0x43, 0x1e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x0e, 0x39, 0x96, 0x00, 0x00, 0x00, 0x11, 0x04, + 0x28, 0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, + 0x00, 0x63, 0x02, 0x00, 0x8d, 0x24, 0x01, 0x00, + 0x21, 0x01, 0x00, 0x30, 0x63, 0x01, 0x00, 0x43, + 0x29, 0x01, 0x00, 0x00, 0x63, 0x07, 0x00, 0x42, + 0x11, 0x01, 0x00, 0x00, 0xb6, 0x63, 0x07, 0x00, + 0xeb, 0x24, 0x03, 0x00, 0x0e, 0x63, 0x01, 0x00, + 0x43, 0x2d, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xec, 0x1c, 0x63, 0x01, 0x00, 0x43, 0x1e, 0x01, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x0e, 0x39, 0x96, + 0x00, 0x00, 0x00, 0x11, 0x04, 0x2e, 0x01, 0x00, + 0x00, 0x21, 0x01, 0x00, 0x30, 0x63, 0x01, 0x00, + 0x43, 0x1e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x0e, 0x66, 0x04, 0x00, 0x43, 0x29, 0x01, 0x00, + 0x00, 0x63, 0x07, 0x00, 0x42, 0x11, 0x01, 0x00, + 0x00, 0xb6, 0x63, 0x07, 0x00, 0xeb, 0x66, 0x05, + 0x00, 0x66, 0x06, 0x00, 0xa5, 0x24, 0x04, 0x00, + 0xc4, 0x08, 0x66, 0x01, 0x00, 0x43, 0x09, 0x01, + 0x00, 0x00, 0x63, 0x08, 0x00, 0x0b, 0x0a, 0x4d, + 0x2f, 0x01, 0x00, 0x00, 0x25, 0x02, 0x00, 0x08, + 0xec, 0x16, 0xc1, 0x00, 0x60, 0x09, 0x00, 0xc1, + 0x01, 0x60, 0x0a, 0x00, 0xc1, 0x02, 0x60, 0x0b, + 0x00, 0xc1, 0x03, 0x60, 0x0c, 0x00, 0x29, 0xb7, + 0xb6, 0xa0, 0xe6, 0xb7, 0xb9, 0xa0, 0x60, 0x04, + 0x00, 0xb7, 0xb6, 0xa0, 0x60, 0x05, 0x00, 0xb7, + 0xb9, 0xa0, 0x60, 0x06, 0x00, 0xb7, 0xba, 0xa0, + 0x60, 0x07, 0x00, 0x0b, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x4d, 0x14, 0x01, 0x00, 0x00, 0xbe, 0x08, + 0x4d, 0x15, 0x01, 0x00, 0x00, 0xba, 0x4d, 0x16, + 0x01, 0x00, 0x00, 0xbe, 0x0c, 0x4d, 0x13, 0x01, + 0x00, 0x00, 0x60, 0x08, 0x00, 0x06, 0x2f, +}; + diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/gen/test_fib.c b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/test_fib.c new file mode 100644 index 0000000..8ac34a2 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/gen/test_fib.c @@ -0,0 +1,80 @@ +/* File generated automatically by the QuickJS-ng compiler. */ + +#include "quickjs-libc.h" + +const uint32_t qjsc_test_fib_size = 294; + +const uint8_t qjsc_test_fib[294] = { + 0x15, 0x0e, 0x01, 0x28, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, + 0x01, 0x0c, 0x71, 0x6a, 0x73, 0x3a, 0x6f, 0x73, + 0x01, 0x04, 0x6f, 0x73, 0x01, 0x0a, 0x69, 0x73, + 0x57, 0x69, 0x6e, 0x01, 0x06, 0x66, 0x69, 0x62, + 0x01, 0x10, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x01, 0x0a, 0x77, 0x69, 0x6e, 0x33, + 0x32, 0x01, 0x0c, 0x2e, 0x2f, 0x66, 0x69, 0x62, + 0x2e, 0x01, 0x06, 0x64, 0x6c, 0x6c, 0x01, 0x04, + 0x73, 0x6f, 0x01, 0x0e, 0x63, 0x6f, 0x6e, 0x73, + 0x6f, 0x6c, 0x65, 0x01, 0x06, 0x6c, 0x6f, 0x67, + 0x01, 0x16, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, + 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x01, 0x10, 0x66, + 0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, + 0xc6, 0x03, 0x01, 0xc8, 0x03, 0x00, 0x00, 0x01, + 0x00, 0xfe, 0x01, 0x00, 0x01, 0x0c, 0x20, 0x0a, + 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, + 0x00, 0x73, 0x00, 0xca, 0x03, 0x00, 0x0d, 0xcc, + 0x03, 0x00, 0x0d, 0xce, 0x03, 0x01, 0x0d, 0x08, + 0xec, 0x02, 0x29, 0x66, 0x00, 0x00, 0x42, 0xe8, + 0x00, 0x00, 0x00, 0x04, 0xe9, 0x00, 0x00, 0x00, + 0xaf, 0xe4, 0x06, 0x11, 0xf4, 0xed, 0x0b, 0x71, + 0x43, 0xe7, 0x00, 0x00, 0x00, 0xe5, 0x0e, 0xee, + 0x24, 0x0e, 0x04, 0xea, 0x00, 0x00, 0x00, 0x43, + 0x5d, 0x00, 0x00, 0x00, 0x66, 0x01, 0x00, 0xec, + 0x08, 0x04, 0xeb, 0x00, 0x00, 0x00, 0xee, 0x06, + 0x04, 0xec, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x36, 0x8c, 0xee, 0xd4, 0x39, 0xed, 0x00, 0x00, + 0x00, 0x43, 0xee, 0x00, 0x00, 0x00, 0x04, 0xef, + 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x39, + 0xed, 0x00, 0x00, 0x00, 0x43, 0xee, 0x00, 0x00, + 0x00, 0x04, 0xf0, 0x00, 0x00, 0x00, 0x66, 0x02, + 0x00, 0xbe, 0x0a, 0xf1, 0x24, 0x02, 0x00, 0x0e, + 0x06, 0x2f, 0xc6, 0x03, 0x01, 0x01, 0x0e, 0x41, + 0x3c, 0x00, 0x39, 0x06, 0x3b, 0x34, 0x10, 0x30, + 0x0f, 0x34, 0x10, 0x2a, 0x20, 0x00, +}; + +static JSContext *JS_NewCustomContext(JSRuntime *rt) +{ + JSContext *ctx = JS_NewContext(rt); + if (!ctx) + return NULL; + { + extern JSModuleDef *js_init_module_os(JSContext *ctx, const char *name); + js_init_module_os(ctx, "qjs:os"); + } + return ctx; +} + +int main(int argc, char **argv) +{ + int r; + JSRuntime *rt; + JSContext *ctx; + r = 0; + rt = JS_NewRuntime(); + js_std_set_worker_new_context_func(JS_NewCustomContext); + js_std_init_handlers(rt); + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); + ctx = JS_NewCustomContext(rt); + js_std_add_helpers(ctx, argc, argv); + js_std_eval_binary(ctx, qjsc_test_fib, qjsc_test_fib_size, 0); + r = js_std_loop(ctx); + if (r) { + js_std_dump_error(ctx); + } + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return r; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/libregexp-opcode.h b/host/cred-script/vendor/rquickjs-sys/quickjs/libregexp-opcode.h new file mode 100644 index 0000000..5c1714a --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/libregexp-opcode.h @@ -0,0 +1,58 @@ +/* + * Regular Expression Engine + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifdef DEF + +DEF(invalid, 1) /* never used */ +DEF(char8, 2) /* 7 bits in fact */ +DEF(char16, 3) +DEF(char32, 5) +DEF(dot, 1) +DEF(any, 1) /* same as dot but match any character including line terminator */ +DEF(line_start, 1) +DEF(line_end, 1) +DEF(goto, 5) +DEF(split_goto_first, 5) +DEF(split_next_first, 5) +DEF(match, 1) +DEF(save_start, 2) /* save start position */ +DEF(save_end, 2) /* save end position, must come after saved_start */ +DEF(save_reset, 3) /* reset save positions */ +DEF(loop, 5) /* decrement the top the stack and goto if != 0 */ +DEF(push_i32, 5) /* push integer on the stack */ +DEF(drop, 1) +DEF(word_boundary, 1) +DEF(not_word_boundary, 1) +DEF(back_reference, 2) +DEF(backward_back_reference, 2) /* must come after back_reference */ +DEF(range, 3) /* variable length */ +DEF(range32, 3) /* variable length */ +DEF(lookahead, 5) +DEF(negative_lookahead, 5) +DEF(push_char_pos, 1) /* push the character position on the stack */ +DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */ +DEF(prev, 1) /* go to the previous char */ +DEF(simple_greedy_quant, 17) + +#endif /* DEF */ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/libregexp.c b/host/cred-script/vendor/rquickjs-sys/quickjs/libregexp.c new file mode 100644 index 0000000..ac60650 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/libregexp.c @@ -0,0 +1,2676 @@ +/* + * Regular Expression Engine + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include + +#include "cutils.h" +#include "libregexp.h" + +/* + TODO: + + - Add a lock step execution mode (=linear time execution guaranteed) + when the regular expression is "simple" i.e. no backreference nor + complicated lookahead. The opcodes are designed for this execution + model. +*/ + +#if defined(TEST) +#define DUMP_REOP +#endif + +typedef enum { +#define DEF(id, size) REOP_ ## id, +#include "libregexp-opcode.h" +#undef DEF + REOP_COUNT, +} REOPCodeEnum; + +#define CAPTURE_COUNT_MAX 255 +#define STACK_SIZE_MAX 255 +/* must be large enough to have a negligible runtime cost and small + enough to call the interrupt callback often. */ +#define INTERRUPT_COUNTER_INIT 10000 + +/* unicode code points */ +#define CP_LS 0x2028 +#define CP_PS 0x2029 + +#define TMP_BUF_SIZE 128 + +// invariant: is_unicode ^ unicode_sets (or neither, but not both) +typedef struct { + DynBuf byte_code; + const uint8_t *buf_ptr; + const uint8_t *buf_end; + const uint8_t *buf_start; + int re_flags; + bool is_unicode; + bool unicode_sets; + bool ignore_case; + bool dotall; + int capture_count; + int total_capture_count; /* -1 = not computed yet */ + int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */ + void *opaque; + DynBuf group_names; + union { + char error_msg[TMP_BUF_SIZE]; + char tmp_buf[TMP_BUF_SIZE]; + } u; +} REParseState; + +typedef struct { +#ifdef DUMP_REOP + const char *name; +#endif + uint8_t size; +} REOpCode; + +static const REOpCode reopcode_info[REOP_COUNT] = { +#ifdef DUMP_REOP +#define DEF(id, size) { #id, size }, +#else +#define DEF(id, size) { size }, +#endif +#include "libregexp-opcode.h" +#undef DEF +}; + +#define RE_HEADER_FLAGS 0 +#define RE_HEADER_CAPTURE_COUNT 2 +#define RE_HEADER_STACK_SIZE 3 +#define RE_HEADER_BYTECODE_LEN 4 + +#define RE_HEADER_LEN 8 + +static inline int lre_is_digit(int c) { + return c >= '0' && c <= '9'; +} + +/* insert 'len' bytes at position 'pos'. Return < 0 if error. */ +static int dbuf_insert(DynBuf *s, int pos, int len) +{ + if (dbuf_realloc(s, s->size + len)) + return -1; + memmove(s->buf + pos + len, s->buf + pos, s->size - pos); + s->size += len; + return 0; +} + +static const uint16_t char_range_d[] = { + 1, + 0x0030, 0x0039 + 1, +}; + +/* code point ranges for Zs,Zl or Zp property */ +static const uint16_t char_range_s[] = { + 10, + 0x0009, 0x000D + 1, + 0x0020, 0x0020 + 1, + 0x00A0, 0x00A0 + 1, + 0x1680, 0x1680 + 1, + 0x2000, 0x200A + 1, + /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */ + /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */ + 0x2028, 0x2029 + 1, + 0x202F, 0x202F + 1, + 0x205F, 0x205F + 1, + 0x3000, 0x3000 + 1, + /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */ + 0xFEFF, 0xFEFF + 1, +}; + +bool lre_is_space(int c) +{ + int i, n, low, high; + n = (countof(char_range_s) - 1) / 2; + for(i = 0; i < n; i++) { + low = char_range_s[2 * i + 1]; + if (c < low) + return false; + high = char_range_s[2 * i + 2]; + if (c < high) + return true; + } + return false; +} + +uint32_t const lre_id_start_table_ascii[4] = { + /* $ A-Z _ a-z */ + 0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE +}; + +uint32_t const lre_id_continue_table_ascii[4] = { + /* $ 0-9 A-Z _ a-z */ + 0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE +}; + + +static const uint16_t char_range_w[] = { + 4, + 0x0030, 0x0039 + 1, + 0x0041, 0x005A + 1, + 0x005F, 0x005F + 1, + 0x0061, 0x007A + 1, +}; + +#define CLASS_RANGE_BASE 0x40000000 + +typedef enum { + CHAR_RANGE_d, + CHAR_RANGE_D, + CHAR_RANGE_s, + CHAR_RANGE_S, + CHAR_RANGE_w, + CHAR_RANGE_W, +} CharRangeEnum; + +static const uint16_t *char_range_table[] = { + char_range_d, + char_range_s, + char_range_w, +}; + +static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c) +{ + bool invert; + const uint16_t *c_pt; + int len, i; + + invert = c & 1; + c_pt = char_range_table[c >> 1]; + len = *c_pt++; + cr_init(cr, s->opaque, lre_realloc); + for(i = 0; i < len * 2; i++) { + if (cr_add_point(cr, c_pt[i])) + goto fail; + } + if (invert) { + if (cr_invert(cr)) + goto fail; + } + return 0; + fail: + cr_free(cr); + return -1; +} + +#ifdef DUMP_REOP +static __maybe_unused void lre_dump_bytecode(const uint8_t *buf, + int buf_len) +{ + int pos, len, opcode, bc_len, re_flags, i; + uint32_t val; + + assert(buf_len >= RE_HEADER_LEN); + + re_flags = lre_get_flags(buf); + bc_len = get_u32(buf + RE_HEADER_BYTECODE_LEN); + assert(bc_len + RE_HEADER_LEN <= buf_len); + printf("flags: 0x%x capture_count=%d stack_size=%d\n", + re_flags, buf[RE_HEADER_CAPTURE_COUNT], buf[RE_HEADER_STACK_SIZE]); + if (re_flags & LRE_FLAG_NAMED_GROUPS) { + const char *p; + p = (char *)buf + RE_HEADER_LEN + bc_len; + printf("named groups: "); + for(i = 1; i < buf[RE_HEADER_CAPTURE_COUNT]; i++) { + if (i != 1) + printf(","); + printf("<%s>", p); + p += strlen(p) + 1; + } + printf("\n"); + assert(p == (char *)(buf + buf_len)); + } + printf("bytecode_len=%d\n", bc_len); + + buf += RE_HEADER_LEN; + pos = 0; + while (pos < bc_len) { + printf("%5u: ", pos); + opcode = buf[pos]; + len = reopcode_info[opcode].size; + if (opcode >= REOP_COUNT) { + printf(" invalid opcode=0x%02x\n", opcode); + break; + } + if ((pos + len) > bc_len) { + printf(" buffer overflow (opcode=0x%02x)\n", opcode); + break; + } + printf("%s", reopcode_info[opcode].name); + switch(opcode) { + case REOP_char8: + val = get_u8(buf + pos + 1); + goto printchar; + case REOP_char16: + val = get_u16(buf + pos + 1); + goto printchar; + case REOP_char32: + val = get_u32(buf + pos + 1); + printchar: + if (val >= ' ' && val <= 126) + printf(" '%c'", val); + else + printf(" 0x%08x", val); + break; + case REOP_goto: + case REOP_split_goto_first: + case REOP_split_next_first: + case REOP_loop: + case REOP_lookahead: + case REOP_negative_lookahead: + val = get_u32(buf + pos + 1); + val += (pos + 5); + printf(" %u", val); + break; + case REOP_simple_greedy_quant: + printf(" %u %u %u %u", + get_u32(buf + pos + 1) + (pos + 17), + get_u32(buf + pos + 1 + 4), + get_u32(buf + pos + 1 + 8), + get_u32(buf + pos + 1 + 12)); + break; + case REOP_save_start: + case REOP_save_end: + case REOP_back_reference: + case REOP_backward_back_reference: + printf(" %u", buf[pos + 1]); + break; + case REOP_save_reset: + printf(" %u %u", buf[pos + 1], buf[pos + 2]); + break; + case REOP_push_i32: + val = get_u32(buf + pos + 1); + printf(" %d", val); + break; + case REOP_range: + { + int n, i; + n = get_u16(buf + pos + 1); + len += n * 4; + for(i = 0; i < n * 2; i++) { + val = get_u16(buf + pos + 3 + i * 2); + printf(" 0x%04x", val); + } + } + break; + case REOP_range32: + { + int n, i; + n = get_u16(buf + pos + 1); + len += n * 8; + for(i = 0; i < n * 2; i++) { + val = get_u32(buf + pos + 3 + i * 4); + printf(" 0x%08x", val); + } + } + break; + default: + break; + } + printf("\n"); + pos += len; + } +} +#endif + +static void re_emit_op(REParseState *s, int op) +{ + dbuf_putc(&s->byte_code, op); +} + +/* return the offset of the u32 value */ +static int re_emit_op_u32(REParseState *s, int op, uint32_t val) +{ + int pos; + dbuf_putc(&s->byte_code, op); + pos = s->byte_code.size; + dbuf_put_u32(&s->byte_code, val); + return pos; +} + +static int re_emit_goto(REParseState *s, int op, uint32_t val) +{ + int pos; + dbuf_putc(&s->byte_code, op); + pos = s->byte_code.size; + dbuf_put_u32(&s->byte_code, val - (pos + 4)); + return pos; +} + +static void re_emit_op_u8(REParseState *s, int op, uint32_t val) +{ + dbuf_putc(&s->byte_code, op); + dbuf_putc(&s->byte_code, val); +} + +static void re_emit_op_u16(REParseState *s, int op, uint32_t val) +{ + dbuf_putc(&s->byte_code, op); + dbuf_put_u16(&s->byte_code, val); +} + +static int JS_PRINTF_FORMAT_ATTR(2, 3) re_parse_error(REParseState *s, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vsnprintf(s->u.error_msg, sizeof(s->u.error_msg), fmt, ap); + va_end(ap); + return -1; +} + +static int re_parse_out_of_memory(REParseState *s) +{ + return re_parse_error(s, "out of memory"); +} + +static int lre_check_size(REParseState *s) +{ + if (s->byte_code.size < 64*1024*1024) + return 0; + return re_parse_out_of_memory(s); +} + +/* If allow_overflow is false, return -1 in case of + overflow. Otherwise return INT32_MAX. */ +static int parse_digits(const uint8_t **pp, bool allow_overflow) +{ + const uint8_t *p; + uint64_t v; + int c; + + p = *pp; + v = 0; + for(;;) { + c = *p; + if (c < '0' || c > '9') + break; + v = v * 10 + c - '0'; + if (v >= INT32_MAX) { + if (allow_overflow) + v = INT32_MAX; + else + return -1; + } + p++; + } + *pp = p; + return v; +} + +static int re_parse_expect(REParseState *s, const uint8_t **pp, int c) +{ + const uint8_t *p; + p = *pp; + if (*p != c) + return re_parse_error(s, "expecting '%c'", c); + p++; + *pp = p; + return 0; +} + +/* Parse an escape sequence, *pp points after the '\': + allow_utf16 value: + 0 : no UTF-16 escapes allowed + 1 : UTF-16 escapes allowed + 2 : UTF-16 escapes allowed and escapes of surrogate pairs are + converted to a unicode character (unicode regexp case). + + Return the unicode char and update *pp if recognized, + return -1 if malformed escape, + return -2 otherwise. */ +int lre_parse_escape(const uint8_t **pp, int allow_utf16) +{ + const uint8_t *p; + uint32_t c; + + p = *pp; + c = *p++; + switch(c) { + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + case 'x': + case 'u': + { + int h, n, i; + uint32_t c1; + + if (*p == '{' && allow_utf16) { + p++; + c = 0; + for(;;) { + h = from_hex(*p++); + if (h < 0) + return -1; + c = (c << 4) | h; + if (c > 0x10FFFF) + return -1; + if (*p == '}') + break; + } + p++; + } else { + if (c == 'x') { + n = 2; + } else { + n = 4; + } + + c = 0; + for(i = 0; i < n; i++) { + h = from_hex(*p++); + if (h < 0) { + return -1; + } + c = (c << 4) | h; + } + if (is_hi_surrogate(c) && + allow_utf16 == 2 && p[0] == '\\' && p[1] == 'u') { + /* convert an escaped surrogate pair into a + unicode char */ + c1 = 0; + for(i = 0; i < 4; i++) { + h = from_hex(p[2 + i]); + if (h < 0) + break; + c1 = (c1 << 4) | h; + } + if (i == 4 && is_lo_surrogate(c1)) { + p += 6; + c = from_surrogate(c, c1); + } + } + } + } + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c -= '0'; + if (allow_utf16 == 2) { + /* only accept \0 not followed by digit */ + if (c != 0 || lre_is_digit(*p)) + return -1; + } else { + /* parse a legacy octal sequence */ + uint32_t v; + v = *p - '0'; + if (v > 7) + break; + c = (c << 3) | v; + p++; + if (c >= 32) + break; + v = *p - '0'; + if (v > 7) + break; + c = (c << 3) | v; + p++; + } + break; + default: + return -2; + } + *pp = p; + return c; +} + +/* XXX: we use the same chars for name and value */ +static bool is_unicode_char(int c) +{ + return ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c == '_')); +} + +static int parse_unicode_property(REParseState *s, CharRange *cr, + const uint8_t **pp, bool is_inv) +{ + const uint8_t *p; + char name[64], value[64]; + char *q; + bool script_ext; + int ret; + + p = *pp; + if (*p != '{') + return re_parse_error(s, "expecting '{' after \\p"); + p++; + q = name; + while (is_unicode_char(*p)) { + if ((q - name) >= sizeof(name) - 1) + goto unknown_property_name; + *q++ = *p++; + } + *q = '\0'; + q = value; + if (*p == '=') { + p++; + while (is_unicode_char(*p)) { + if ((q - value) >= sizeof(value) - 1) + return re_parse_error(s, "unknown unicode property value"); + *q++ = *p++; + } + } + *q = '\0'; + if (*p != '}') + return re_parse_error(s, "expecting '}'"); + p++; + // printf("name=%s value=%s\n", name, value); + + if (!strcmp(name, "Script") || !strcmp(name, "sc")) { + script_ext = false; + goto do_script; + } else if (!strcmp(name, "Script_Extensions") || !strcmp(name, "scx")) { + script_ext = true; + do_script: + cr_init(cr, s->opaque, lre_realloc); + ret = unicode_script(cr, value, script_ext); + if (ret) { + cr_free(cr); + if (ret == -2) + return re_parse_error(s, "unknown unicode script"); + else + goto out_of_memory; + } + } else if (!strcmp(name, "General_Category") || !strcmp(name, "gc")) { + cr_init(cr, s->opaque, lre_realloc); + ret = unicode_general_category(cr, value); + if (ret) { + cr_free(cr); + if (ret == -2) + return re_parse_error(s, "unknown unicode general category"); + else + goto out_of_memory; + } + } else if (value[0] == '\0') { + cr_init(cr, s->opaque, lre_realloc); + ret = unicode_general_category(cr, name); + if (ret == -1) { + cr_free(cr); + goto out_of_memory; + } + if (ret < 0) { + ret = unicode_prop(cr, name); + if (ret) { + cr_free(cr); + if (ret == -2) + goto unknown_property_name; + else + goto out_of_memory; + } + } + } else { + unknown_property_name: + return re_parse_error(s, "unknown unicode property name"); + } + + if (is_inv) { + if (cr_invert(cr)) { + cr_free(cr); + return -1; + } + } + *pp = p; + return 0; + out_of_memory: + return re_parse_out_of_memory(s); +} + +/* return -1 if error otherwise the character or a class range + (CLASS_RANGE_BASE). In case of class range, 'cr' is + initialized. Otherwise, it is ignored. */ +static int get_class_atom(REParseState *s, CharRange *cr, + const uint8_t **pp, bool inclass) +{ + const uint8_t *p, *p_next; + uint32_t c; + int ret; + + p = *pp; + + c = *p; + switch(c) { + case '\\': + p++; + if (p >= s->buf_end) + goto unexpected_end; + c = *p++; + switch(c) { + case 'd': + c = CHAR_RANGE_d; + goto class_range; + case 'D': + c = CHAR_RANGE_D; + goto class_range; + case 's': + c = CHAR_RANGE_s; + goto class_range; + case 'S': + c = CHAR_RANGE_S; + goto class_range; + case 'w': + c = CHAR_RANGE_w; + goto class_range; + case 'W': + c = CHAR_RANGE_W; + class_range: + if (cr_init_char_range(s, cr, c)) + return -1; + c = CLASS_RANGE_BASE; + break; + case 'c': + c = *p; + if ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (((c >= '0' && c <= '9') || c == '_') && + inclass && !s->is_unicode)) { /* Annex B.1.4 */ + c &= 0x1f; + p++; + } else if (s->is_unicode) { + goto invalid_escape; + } else { + /* otherwise return '\' and 'c' */ + p--; + c = '\\'; + } + break; + case 'p': + case 'P': + if (s->is_unicode) { + if (parse_unicode_property(s, cr, &p, (c == 'P'))) + return -1; + c = CLASS_RANGE_BASE; + break; + } + /* fall thru */ + default: + p--; + ret = lre_parse_escape(&p, s->is_unicode * 2); + if (ret >= 0) { + c = ret; + } else { + if (ret == -2 && *p != '\0' && strchr("^$\\.*+?()[]{}|/", *p)) { + /* always valid to escape these characters */ + goto normal_char; + } else if (s->is_unicode) { + // special case: allowed inside [] but not outside + if (ret == -2 && *p == '-' && inclass) + goto normal_char; + invalid_escape: + return re_parse_error(s, "invalid escape sequence in regular expression"); + } else { + /* just ignore the '\' */ + goto normal_char; + } + } + break; + } + break; + case '\0': + if (p >= s->buf_end) { + unexpected_end: + return re_parse_error(s, "unexpected end"); + } + /* fall thru */ + default: + normal_char: + p++; + if (c >= 0x80) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) + return re_parse_error(s, "invalid UTF-8 sequence"); + p = p_next; + if (c > 0xFFFF && !s->is_unicode) { + // TODO(chqrlie): should handle non BMP-1 code points in + // the calling function and no require the source string + // to be CESU-8 encoded if not s->is_unicode + return re_parse_error(s, "malformed unicode char"); + } + } + break; + } + *pp = p; + return c; +} + +static int re_emit_range(REParseState *s, const CharRange *cr) +{ + int len, i; + uint32_t high; + + len = (unsigned)cr->len / 2; + if (len >= 65535) + return re_parse_error(s, "too many ranges"); + if (len == 0) { + /* not sure it can really happen. Emit a match that is always + false */ + re_emit_op_u32(s, REOP_char32, -1); + } else { + high = cr->points[cr->len - 1]; + if (high == UINT32_MAX) + high = cr->points[cr->len - 2]; + if (high <= 0xffff) { + /* can use 16 bit ranges with the conversion that 0xffff = + infinity */ + re_emit_op_u16(s, REOP_range, len); + for(i = 0; i < cr->len; i += 2) { + dbuf_put_u16(&s->byte_code, cr->points[i]); + high = cr->points[i + 1] - 1; + if (high == UINT32_MAX - 1) + high = 0xffff; + dbuf_put_u16(&s->byte_code, high); + } + } else { + re_emit_op_u16(s, REOP_range32, len); + for(i = 0; i < cr->len; i += 2) { + dbuf_put_u32(&s->byte_code, cr->points[i]); + dbuf_put_u32(&s->byte_code, cr->points[i + 1] - 1); + } + } + } + return 0; +} + +// s->unicode turns patterns like []] into syntax errors +// s->unicode_sets turns more patterns into errors, like [a-] or [[] +static int re_parse_char_class(REParseState *s, const uint8_t **pp) +{ + const uint8_t *p; + uint32_t c1, c2; + CharRange cr_s, *cr = &cr_s; + CharRange cr1_s, *cr1 = &cr1_s; + bool invert; + + cr_init(cr, s->opaque, lre_realloc); + p = *pp; + p++; /* skip '[' */ + + if (s->unicode_sets) { + static const char verboten[] = + "()[{}/-|" "\0" + "&&!!##$$%%**++,,..::;;<<==>>??@@``~~" "\0" + "^^^_^^"; + const char *s = verboten; + int n = 1; + do { + if (!memcmp(s, p, n)) + if (p[n] == ']') + goto invalid_class_range; + s += n; + if (!*s) { + s++; + n++; + } + } while (n < 4); + } + + invert = false; + if (*p == '^') { + p++; + invert = true; + } + + for(;;) { + if (*p == ']') + break; + c1 = get_class_atom(s, cr1, &p, true); + if ((int)c1 < 0) + goto fail; + if (*p == '-' && p[1] == ']' && s->unicode_sets) { + if (c1 >= CLASS_RANGE_BASE) + cr_free(cr1); + goto invalid_class_range; + } + if (*p == '-' && p[1] != ']') { + const uint8_t *p0 = p + 1; + if (c1 >= CLASS_RANGE_BASE) { + if (s->is_unicode) { + cr_free(cr1); + goto invalid_class_range; + } + /* Annex B: match '-' character */ + goto class_atom; + } + c2 = get_class_atom(s, cr1, &p0, true); + if ((int)c2 < 0) + goto fail; + if (c2 >= CLASS_RANGE_BASE) { + cr_free(cr1); + if (s->is_unicode) { + goto invalid_class_range; + } + /* Annex B: match '-' character */ + goto class_atom; + } + p = p0; + if (c2 < c1) { + invalid_class_range: + re_parse_error(s, "invalid class range"); + goto fail; + } + if (cr_union_interval(cr, c1, c2)) + goto memory_error; + } else { + class_atom: + if (c1 >= CLASS_RANGE_BASE) { + int ret; + ret = cr_union1(cr, cr1->points, cr1->len); + cr_free(cr1); + if (ret) + goto memory_error; + } else { + if (cr_union_interval(cr, c1, c1)) + goto memory_error; + } + } + } + if (s->ignore_case) { + if (cr_regexp_canonicalize(cr, s->is_unicode)) + goto memory_error; + } + if (invert) { + if (cr_invert(cr)) + goto memory_error; + } + if (re_emit_range(s, cr)) + goto fail; + cr_free(cr); + p++; /* skip ']' */ + *pp = p; + return 0; + memory_error: + re_parse_out_of_memory(s); + fail: + cr_free(cr); + return -1; +} + +/* Return: + - true if the opcodes may not advance the char pointer + - false if the opcodes always advance the char pointer +*/ +static bool re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len) +{ + int pos, opcode, len; + uint32_t val; + bool ret; + + ret = true; + pos = 0; + + while (pos < bc_buf_len) { + opcode = bc_buf[pos]; + len = reopcode_info[opcode].size; + switch(opcode) { + case REOP_range: + val = get_u16(bc_buf + pos + 1); + len += val * 4; + goto simple_char; + case REOP_range32: + val = get_u16(bc_buf + pos + 1); + len += val * 8; + goto simple_char; + case REOP_char32: + case REOP_char16: + case REOP_char8: + case REOP_dot: + case REOP_any: + simple_char: + ret = false; + break; + case REOP_line_start: + case REOP_line_end: + case REOP_push_i32: + case REOP_push_char_pos: + case REOP_drop: + case REOP_word_boundary: + case REOP_not_word_boundary: + case REOP_prev: + /* no effect */ + break; + case REOP_save_start: + case REOP_save_end: + case REOP_save_reset: + case REOP_back_reference: + case REOP_backward_back_reference: + break; + default: + /* safe behvior: we cannot predict the outcome */ + return true; + } + pos += len; + } + return ret; +} + +/* return -1 if a simple quantifier cannot be used. Otherwise return + the number of characters in the atom. */ +static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len) +{ + int pos, opcode, len, count; + uint32_t val; + + count = 0; + pos = 0; + while (pos < bc_buf_len) { + opcode = bc_buf[pos]; + len = reopcode_info[opcode].size; + switch(opcode) { + case REOP_range: + val = get_u16(bc_buf + pos + 1); + len += val * 4; + goto simple_char; + case REOP_range32: + val = get_u16(bc_buf + pos + 1); + len += val * 8; + goto simple_char; + case REOP_char32: + case REOP_char16: + case REOP_char8: + case REOP_dot: + case REOP_any: + simple_char: + count++; + break; + case REOP_line_start: + case REOP_line_end: + case REOP_word_boundary: + case REOP_not_word_boundary: + break; + default: + return -1; + } + pos += len; + } + return count; +} + +/* '*pp' is the first char after '<' */ +static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp) +{ + const uint8_t *p, *p_next; + uint32_t c, d; + char *q; + + p = *pp; + q = buf; + for(;;) { + c = *p++; + if (c == '\\') { + if (*p != 'u') + return -1; + c = lre_parse_escape(&p, 2); // accept surrogate pairs + if ((int)c < 0) + return -1; + } else if (c == '>') { + break; + } else if (c >= 0x80) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) + return -1; + p = p_next; + if (is_hi_surrogate(c)) { + d = utf8_decode(p, &p_next); + if (is_lo_surrogate(d)) { + c = from_surrogate(c, d); + p = p_next; + } + } + } + if (q == buf) { + if (!lre_js_is_ident_first(c)) + return -1; + } else { + if (!lre_js_is_ident_next(c)) + return -1; + } + if ((q - buf + UTF8_CHAR_LEN_MAX + 1) > buf_size) + return -1; + if (c < 0x80) { + *q++ = c; + } else { + q += utf8_encode((uint8_t*)q, c); + } + } + if (q == buf) + return -1; + *q = '\0'; + *pp = p; + return 0; +} + +/* if capture_name = NULL: return the number of captures + 1. + Otherwise, return the capture index corresponding to capture_name + or -1 if none */ +static int re_parse_captures(REParseState *s, int *phas_named_captures, + const char *capture_name) +{ + const uint8_t *p; + int capture_index; + char name[TMP_BUF_SIZE]; + + capture_index = 1; + *phas_named_captures = 0; + for (p = s->buf_start; p < s->buf_end; p++) { + switch (*p) { + case '(': + if (p[1] == '?') { + if (p[2] == '<' && p[3] != '=' && p[3] != '!') { + *phas_named_captures = 1; + /* potential named capture */ + if (capture_name) { + p += 3; + if (re_parse_group_name(name, sizeof(name), &p) == 0) { + if (!strcmp(name, capture_name)) + return capture_index; + } + } + capture_index++; + if (capture_index >= CAPTURE_COUNT_MAX) + goto done; + } + } else { + capture_index++; + if (capture_index >= CAPTURE_COUNT_MAX) + goto done; + } + break; + case '\\': + p++; + break; + case '[': + for (p += 1 + (*p == ']'); p < s->buf_end && *p != ']'; p++) { + if (*p == '\\') + p++; + } + break; + } + } + done: + if (capture_name) + return -1; + else + return capture_index; +} + +static int re_count_captures(REParseState *s) +{ + if (s->total_capture_count < 0) { + s->total_capture_count = re_parse_captures(s, &s->has_named_captures, + NULL); + } + return s->total_capture_count; +} + +static bool re_has_named_captures(REParseState *s) +{ + if (s->has_named_captures < 0) + re_count_captures(s); + return s->has_named_captures; +} + +static int find_group_name(REParseState *s, const char *name) +{ + const char *p, *buf_end; + size_t len, name_len; + int capture_index; + + p = (char *)s->group_names.buf; + if (!p) return -1; + buf_end = (char *)s->group_names.buf + s->group_names.size; + name_len = strlen(name); + capture_index = 1; + while (p < buf_end) { + len = strlen(p); + if (len == name_len && memcmp(name, p, name_len) == 0) + return capture_index; + p += len + 1; + capture_index++; + } + return -1; +} + +static int re_parse_disjunction(REParseState *s, bool is_backward_dir); + +static int re_parse_term(REParseState *s, bool is_backward_dir) +{ + const uint8_t *p; + int c, last_atom_start, quant_min, quant_max, last_capture_count; + bool greedy, add_zero_advance_check, is_neg, is_backward_lookahead; + CharRange cr_s, *cr = &cr_s; + + if (lre_check_size(s)) + return -1; + last_atom_start = -1; + last_capture_count = 0; + p = s->buf_ptr; + c = *p; + switch(c) { + case '^': + p++; + re_emit_op(s, REOP_line_start); + break; + case '$': + p++; + re_emit_op(s, REOP_line_end); + break; + case '.': + p++; + last_atom_start = s->byte_code.size; + last_capture_count = s->capture_count; + if (is_backward_dir) + re_emit_op(s, REOP_prev); + re_emit_op(s, s->dotall ? REOP_any : REOP_dot); + if (is_backward_dir) + re_emit_op(s, REOP_prev); + break; + case '{': + if (s->is_unicode) { + return re_parse_error(s, "syntax error"); + } else if (!lre_is_digit(p[1])) { + /* Annex B: we accept '{' not followed by digits as a + normal atom */ + goto parse_class_atom; + } else { + const uint8_t *p1 = p + 1; + /* Annex B: error if it is like a repetition count */ + parse_digits(&p1, true); + if (*p1 == ',') { + p1++; + if (lre_is_digit(*p1)) { + parse_digits(&p1, true); + } + } + if (*p1 != '}') { + goto parse_class_atom; + } + } + /* fall thru */ + case '*': + case '+': + case '?': + return re_parse_error(s, "nothing to repeat"); + case '(': + if (p[1] == '?') { + if (p[2] == ':') { + p += 3; + last_atom_start = s->byte_code.size; + last_capture_count = s->capture_count; + s->buf_ptr = p; + if (re_parse_disjunction(s, is_backward_dir)) + return -1; + p = s->buf_ptr; + if (re_parse_expect(s, &p, ')')) + return -1; + } else if ((p[2] == '=' || p[2] == '!')) { + is_neg = (p[2] == '!'); + is_backward_lookahead = false; + p += 3; + goto lookahead; + } else if (p[2] == '<' && + (p[3] == '=' || p[3] == '!')) { + int pos; + is_neg = (p[3] == '!'); + is_backward_lookahead = true; + p += 4; + /* lookahead */ + lookahead: + /* Annex B allows lookahead to be used as an atom for + the quantifiers */ + if (!s->is_unicode && !is_backward_lookahead) { + last_atom_start = s->byte_code.size; + last_capture_count = s->capture_count; + } + pos = re_emit_op_u32(s, REOP_lookahead + is_neg, 0); + s->buf_ptr = p; + if (re_parse_disjunction(s, is_backward_lookahead)) + return -1; + p = s->buf_ptr; + if (re_parse_expect(s, &p, ')')) + return -1; + re_emit_op(s, REOP_match); + /* jump after the 'match' after the lookahead is successful */ + if (dbuf_error(&s->byte_code)) + return -1; + put_u32(s->byte_code.buf + pos, s->byte_code.size - (pos + 4)); + } else if (p[2] == '<') { + p += 3; + if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf), + &p)) { + return re_parse_error(s, "invalid group name"); + } + if (find_group_name(s, s->u.tmp_buf) > 0) { + return re_parse_error(s, "duplicate group name"); + } + /* group name with a trailing zero */ + dbuf_put(&s->group_names, (uint8_t *)s->u.tmp_buf, + strlen(s->u.tmp_buf) + 1); + s->has_named_captures = 1; + goto parse_capture; + } else { + return re_parse_error(s, "invalid group"); + } + } else { + int capture_index; + p++; + /* capture without group name */ + dbuf_putc(&s->group_names, 0); + parse_capture: + if (s->capture_count >= CAPTURE_COUNT_MAX) + return re_parse_error(s, "too many captures"); + last_atom_start = s->byte_code.size; + last_capture_count = s->capture_count; + capture_index = s->capture_count++; + re_emit_op_u8(s, REOP_save_start + is_backward_dir, + capture_index); + + s->buf_ptr = p; + if (re_parse_disjunction(s, is_backward_dir)) + return -1; + p = s->buf_ptr; + + re_emit_op_u8(s, REOP_save_start + 1 - is_backward_dir, + capture_index); + + if (re_parse_expect(s, &p, ')')) + return -1; + } + break; + case '\\': + switch(p[1]) { + case 'b': + case 'B': + re_emit_op(s, REOP_word_boundary + (p[1] != 'b')); + p += 2; + break; + case 'k': + { + const uint8_t *p1; + int dummy_res; + + p1 = p; + if (p1[2] != '<') { + /* annex B: we tolerate invalid group names in non + unicode mode if there is no named capture + definition */ + if (s->is_unicode || re_has_named_captures(s)) + return re_parse_error(s, "expecting group name"); + else + goto parse_class_atom; + } + p1 += 3; + if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf), + &p1)) { + if (s->is_unicode || re_has_named_captures(s)) + return re_parse_error(s, "invalid group name"); + else + goto parse_class_atom; + } + c = find_group_name(s, s->u.tmp_buf); + if (c < 0) { + /* no capture name parsed before, try to look + after (inefficient, but hopefully not common */ + c = re_parse_captures(s, &dummy_res, s->u.tmp_buf); + if (c < 0) { + if (s->is_unicode || re_has_named_captures(s)) + return re_parse_error(s, "group name not defined"); + else + goto parse_class_atom; + } + } + p = p1; + } + goto emit_back_reference; + case '0': + p += 2; + c = 0; + if (s->is_unicode) { + if (lre_is_digit(*p)) { + return re_parse_error(s, "invalid decimal escape in regular expression"); + } + } else { + /* Annex B.1.4: accept legacy octal */ + if (*p >= '0' && *p <= '7') { + c = *p++ - '0'; + if (*p >= '0' && *p <= '7') { + c = (c << 3) + *p++ - '0'; + } + } + } + goto normal_char; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': + case '9': + { + const uint8_t *q = ++p; + + c = parse_digits(&p, false); + if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) { + if (!s->is_unicode) { + /* Annex B.1.4: accept legacy octal */ + p = q; + if (*p <= '7') { + c = 0; + if (*p <= '3') + c = *p++ - '0'; + if (*p >= '0' && *p <= '7') { + c = (c << 3) + *p++ - '0'; + if (*p >= '0' && *p <= '7') { + c = (c << 3) + *p++ - '0'; + } + } + } else { + c = *p++; + } + goto normal_char; + } + return re_parse_error(s, "back reference out of range in regular expression"); + } + emit_back_reference: + last_atom_start = s->byte_code.size; + last_capture_count = s->capture_count; + re_emit_op_u8(s, REOP_back_reference + is_backward_dir, c); + } + break; + default: + goto parse_class_atom; + } + break; + case '[': + last_atom_start = s->byte_code.size; + last_capture_count = s->capture_count; + if (is_backward_dir) + re_emit_op(s, REOP_prev); + if (re_parse_char_class(s, &p)) + return -1; + if (is_backward_dir) + re_emit_op(s, REOP_prev); + break; + case ']': + case '}': + if (s->is_unicode) + return re_parse_error(s, "syntax error"); + goto parse_class_atom; + default: + parse_class_atom: + c = get_class_atom(s, cr, &p, false); + if ((int)c < 0) + return -1; + normal_char: + last_atom_start = s->byte_code.size; + last_capture_count = s->capture_count; + if (is_backward_dir) + re_emit_op(s, REOP_prev); + if (c >= CLASS_RANGE_BASE) { + int ret; + /* Note: canonicalization is not needed */ + ret = re_emit_range(s, cr); + cr_free(cr); + if (ret) + return -1; + } else { + if (s->ignore_case) + c = lre_canonicalize(c, s->is_unicode); + if (c <= 0x7f) + re_emit_op_u8(s, REOP_char8, c); + else if (c <= 0xffff) + re_emit_op_u16(s, REOP_char16, c); + else + re_emit_op_u32(s, REOP_char32, c); + } + if (is_backward_dir) + re_emit_op(s, REOP_prev); + break; + } + + /* quantifier */ + if (last_atom_start >= 0) { + c = *p; + switch(c) { + case '*': + p++; + quant_min = 0; + quant_max = INT32_MAX; + goto quantifier; + case '+': + p++; + quant_min = 1; + quant_max = INT32_MAX; + goto quantifier; + case '?': + p++; + quant_min = 0; + quant_max = 1; + goto quantifier; + case '{': + { + const uint8_t *p1 = p; + /* As an extension (see ES6 annex B), we accept '{' not + followed by digits as a normal atom */ + if (!lre_is_digit(p[1])) { + if (s->is_unicode) + goto invalid_quant_count; + break; + } + p++; + quant_min = parse_digits(&p, true); + quant_max = quant_min; + if (*p == ',') { + p++; + if (lre_is_digit(*p)) { + quant_max = parse_digits(&p, true); + if (quant_max < quant_min) { + invalid_quant_count: + return re_parse_error(s, "invalid repetition count"); + } + } else { + quant_max = INT32_MAX; /* infinity */ + } + } + if (*p != '}' && !s->is_unicode) { + /* Annex B: normal atom if invalid '{' syntax */ + p = p1; + break; + } + if (re_parse_expect(s, &p, '}')) + return -1; + } + quantifier: + greedy = true; + if (*p == '?') { + p++; + greedy = false; + } + if (last_atom_start < 0) { + return re_parse_error(s, "nothing to repeat"); + } + if (greedy) { + int len, pos; + + if (quant_max > 0) { + /* specific optimization for simple quantifiers */ + if (dbuf_error(&s->byte_code)) + goto out_of_memory; + len = re_is_simple_quantifier(s->byte_code.buf + last_atom_start, + s->byte_code.size - last_atom_start); + if (len > 0) { + re_emit_op(s, REOP_match); + + if (dbuf_insert(&s->byte_code, last_atom_start, 17)) + goto out_of_memory; + pos = last_atom_start; + s->byte_code.buf[pos++] = REOP_simple_greedy_quant; + put_u32(&s->byte_code.buf[pos], + s->byte_code.size - last_atom_start - 17); + pos += 4; + put_u32(&s->byte_code.buf[pos], quant_min); + pos += 4; + put_u32(&s->byte_code.buf[pos], quant_max); + pos += 4; + put_u32(&s->byte_code.buf[pos], len); + pos += 4; + goto done; + } + } + + if (dbuf_error(&s->byte_code)) + goto out_of_memory; + } + /* the spec tells that if there is no advance when + running the atom after the first quant_min times, + then there is no match. We remove this test when we + are sure the atom always advances the position. */ + add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start, + s->byte_code.size - last_atom_start); + + { + int len, pos; + len = s->byte_code.size - last_atom_start; + if (quant_min == 0) { + /* need to reset the capture in case the atom is + not executed */ + if (last_capture_count != s->capture_count) { + if (dbuf_insert(&s->byte_code, last_atom_start, 3)) + goto out_of_memory; + s->byte_code.buf[last_atom_start++] = REOP_save_reset; + s->byte_code.buf[last_atom_start++] = last_capture_count; + s->byte_code.buf[last_atom_start++] = s->capture_count - 1; + } + if (quant_max == 0) { + s->byte_code.size = last_atom_start; + } else if (quant_max == 1 || quant_max == INT32_MAX) { + bool has_goto = (quant_max == INT32_MAX); + if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check)) + goto out_of_memory; + s->byte_code.buf[last_atom_start] = REOP_split_goto_first + + greedy; + put_u32(s->byte_code.buf + last_atom_start + 1, + len + 5 * has_goto + add_zero_advance_check * 2); + if (add_zero_advance_check) { + s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos; + re_emit_op(s, REOP_check_advance); + } + if (has_goto) + re_emit_goto(s, REOP_goto, last_atom_start); + } else { + if (dbuf_insert(&s->byte_code, last_atom_start, 10 + add_zero_advance_check)) + goto out_of_memory; + pos = last_atom_start; + s->byte_code.buf[pos++] = REOP_push_i32; + put_u32(s->byte_code.buf + pos, quant_max); + pos += 4; + s->byte_code.buf[pos++] = REOP_split_goto_first + greedy; + put_u32(s->byte_code.buf + pos, len + 5 + add_zero_advance_check * 2); + pos += 4; + if (add_zero_advance_check) { + s->byte_code.buf[pos++] = REOP_push_char_pos; + re_emit_op(s, REOP_check_advance); + } + re_emit_goto(s, REOP_loop, last_atom_start + 5); + re_emit_op(s, REOP_drop); + } + } else if (quant_min == 1 && quant_max == INT32_MAX && + !add_zero_advance_check) { + re_emit_goto(s, REOP_split_next_first - greedy, + last_atom_start); + } else { + if (quant_min == 1) { + /* nothing to add */ + } else { + if (dbuf_insert(&s->byte_code, last_atom_start, 5)) + goto out_of_memory; + s->byte_code.buf[last_atom_start] = REOP_push_i32; + put_u32(s->byte_code.buf + last_atom_start + 1, + quant_min); + last_atom_start += 5; + re_emit_goto(s, REOP_loop, last_atom_start); + re_emit_op(s, REOP_drop); + } + if (quant_max == INT32_MAX) { + pos = s->byte_code.size; + re_emit_op_u32(s, REOP_split_goto_first + greedy, + len + 5 + add_zero_advance_check * 2); + if (add_zero_advance_check) + re_emit_op(s, REOP_push_char_pos); + /* copy the atom */ + dbuf_put_self(&s->byte_code, last_atom_start, len); + if (add_zero_advance_check) + re_emit_op(s, REOP_check_advance); + re_emit_goto(s, REOP_goto, pos); + } else if (quant_max > quant_min) { + re_emit_op_u32(s, REOP_push_i32, quant_max - quant_min); + pos = s->byte_code.size; + re_emit_op_u32(s, REOP_split_goto_first + greedy, + len + 5 + add_zero_advance_check * 2); + if (add_zero_advance_check) + re_emit_op(s, REOP_push_char_pos); + /* copy the atom */ + dbuf_put_self(&s->byte_code, last_atom_start, len); + if (add_zero_advance_check) + re_emit_op(s, REOP_check_advance); + re_emit_goto(s, REOP_loop, pos); + re_emit_op(s, REOP_drop); + } + } + last_atom_start = -1; + } + break; + default: + break; + } + } + done: + s->buf_ptr = p; + return 0; + out_of_memory: + return re_parse_out_of_memory(s); +} + +static int re_parse_alternative(REParseState *s, bool is_backward_dir) +{ + const uint8_t *p; + int ret; + size_t start, term_start, end, term_size; + + if (lre_check_size(s)) + return -1; + start = s->byte_code.size; + for(;;) { + p = s->buf_ptr; + if (p >= s->buf_end) + break; + if (*p == '|' || *p == ')') + break; + term_start = s->byte_code.size; + ret = re_parse_term(s, is_backward_dir); + if (ret) + return ret; + if (is_backward_dir) { + /* reverse the order of the terms (XXX: inefficient, but + speed is not really critical here) */ + end = s->byte_code.size; + term_size = end - term_start; + if (dbuf_realloc(&s->byte_code, end + term_size)) + return -1; + memmove(s->byte_code.buf + start + term_size, + s->byte_code.buf + start, + end - start); + memcpy(s->byte_code.buf + start, s->byte_code.buf + end, + term_size); + } + } + return 0; +} + +static int re_parse_disjunction(REParseState *s, bool is_backward_dir) +{ + int start, len, pos; + + if (lre_check_stack_overflow(s->opaque, 0)) + return re_parse_error(s, "stack overflow"); + if (lre_check_size(s)) + return -1; + start = s->byte_code.size; + if (re_parse_alternative(s, is_backward_dir)) + return -1; + while (*s->buf_ptr == '|') { + s->buf_ptr++; + + len = s->byte_code.size - start; + + /* insert a split before the first alternative */ + if (dbuf_insert(&s->byte_code, start, 5)) { + return re_parse_out_of_memory(s); + } + s->byte_code.buf[start] = REOP_split_next_first; + put_u32(s->byte_code.buf + start + 1, len + 5); + + pos = re_emit_op_u32(s, REOP_goto, 0); + + if (re_parse_alternative(s, is_backward_dir)) + return -1; + + /* patch the goto */ + len = s->byte_code.size - (pos + 4); + put_u32(s->byte_code.buf + pos, len); + } + return 0; +} + +/* the control flow is recursive so the analysis can be linear */ +static int lre_compute_stack_size(const uint8_t *bc_buf, int bc_buf_len) +{ + int stack_size, stack_size_max, pos, opcode, len; + uint32_t val; + + stack_size = 0; + stack_size_max = 0; + bc_buf += RE_HEADER_LEN; + bc_buf_len -= RE_HEADER_LEN; + pos = 0; + while (pos < bc_buf_len) { + opcode = bc_buf[pos]; + len = reopcode_info[opcode].size; + assert(opcode < REOP_COUNT); + assert((pos + len) <= bc_buf_len); + switch(opcode) { + case REOP_push_i32: + case REOP_push_char_pos: + stack_size++; + if (stack_size > stack_size_max) { + if (stack_size > STACK_SIZE_MAX) + return -1; + stack_size_max = stack_size; + } + break; + case REOP_drop: + case REOP_check_advance: + assert(stack_size > 0); + stack_size--; + break; + case REOP_range: + val = get_u16(bc_buf + pos + 1); + len += val * 4; + break; + case REOP_range32: + val = get_u16(bc_buf + pos + 1); + len += val * 8; + break; + } + pos += len; + } + return stack_size_max; +} + +/* 'buf' must be a zero terminated UTF-8 string of length buf_len. + Return NULL if error and allocate an error message in *perror_msg, + otherwise the compiled bytecode and its length in plen. +*/ +uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, + const char *buf, size_t buf_len, int re_flags, + void *opaque) +{ + REParseState s_s, *s = &s_s; + int stack_size; + bool is_sticky; + + memset(s, 0, sizeof(*s)); + s->opaque = opaque; + s->buf_ptr = (const uint8_t *)buf; + s->buf_end = s->buf_ptr + buf_len; + s->buf_start = s->buf_ptr; + s->re_flags = re_flags; + s->is_unicode = ((re_flags & LRE_FLAG_UNICODE) != 0); + is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0); + s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0); + s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0); + s->unicode_sets = ((re_flags & LRE_FLAG_UNICODE_SETS) != 0); + s->capture_count = 1; + s->total_capture_count = -1; + s->has_named_captures = -1; + + dbuf_init2(&s->byte_code, opaque, lre_realloc); + dbuf_init2(&s->group_names, opaque, lre_realloc); + + dbuf_put_u16(&s->byte_code, re_flags); /* first element is the flags */ + dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */ + dbuf_putc(&s->byte_code, 0); /* stack size */ + dbuf_put_u32(&s->byte_code, 0); /* bytecode length */ + + if (!is_sticky) { + /* iterate thru all positions (about the same as .*?( ... ) ) + . We do it without an explicit loop so that lock step + thread execution will be possible in an optimized + implementation */ + re_emit_op_u32(s, REOP_split_goto_first, 1 + 5); + re_emit_op(s, REOP_any); + re_emit_op_u32(s, REOP_goto, -(5 + 1 + 5)); + } + re_emit_op_u8(s, REOP_save_start, 0); + + if (re_parse_disjunction(s, false)) { + error: + dbuf_free(&s->byte_code); + dbuf_free(&s->group_names); + js__pstrcpy(error_msg, error_msg_size, s->u.error_msg); + *plen = 0; + return NULL; + } + + re_emit_op_u8(s, REOP_save_end, 0); + + re_emit_op(s, REOP_match); + + if (*s->buf_ptr != '\0') { + re_parse_error(s, "extraneous characters at the end"); + goto error; + } + + if (dbuf_error(&s->byte_code)) { + re_parse_out_of_memory(s); + goto error; + } + + stack_size = lre_compute_stack_size(s->byte_code.buf, s->byte_code.size); + if (stack_size < 0) { + re_parse_error(s, "too many imbricated quantifiers"); + goto error; + } + + s->byte_code.buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count; + s->byte_code.buf[RE_HEADER_STACK_SIZE] = stack_size; + put_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN, + s->byte_code.size - RE_HEADER_LEN); + + /* add the named groups if needed */ + if (s->group_names.size > (s->capture_count - 1)) { + dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size); + put_u16(s->byte_code.buf + RE_HEADER_FLAGS, + LRE_FLAG_NAMED_GROUPS | lre_get_flags(s->byte_code.buf)); + } + dbuf_free(&s->group_names); + +#ifdef DUMP_REOP + lre_dump_bytecode(s->byte_code.buf, s->byte_code.size); +#endif + + error_msg[0] = '\0'; + *plen = s->byte_code.size; + return s->byte_code.buf; +} + +static bool is_line_terminator(uint32_t c) +{ + return (c == '\n' || c == '\r' || c == CP_LS || c == CP_PS); +} + +static bool is_word_char(uint32_t c) +{ + return ((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c == '_')); +} + +#define GET_CHAR(c, cptr, cbuf_end, cbuf_type) \ + do { \ + if (cbuf_type == 0) { \ + c = *cptr++; \ + } else { \ + const uint16_t *_p = (const uint16_t *)cptr; \ + const uint16_t *_end = (const uint16_t *)cbuf_end; \ + c = *_p++; \ + if (is_hi_surrogate(c)) \ + if (cbuf_type == 2) \ + if (_p < _end) \ + if (is_lo_surrogate(*_p)) \ + c = from_surrogate(c, *_p++); \ + cptr = (const void *)_p; \ + } \ + } while (0) + +#define PEEK_CHAR(c, cptr, cbuf_end, cbuf_type) \ + do { \ + if (cbuf_type == 0) { \ + c = cptr[0]; \ + } else { \ + const uint16_t *_p = (const uint16_t *)cptr; \ + const uint16_t *_end = (const uint16_t *)cbuf_end; \ + c = *_p++; \ + if (is_hi_surrogate(c)) \ + if (cbuf_type == 2) \ + if (_p < _end) \ + if (is_lo_surrogate(*_p)) \ + c = from_surrogate(c, *_p); \ + } \ + } while (0) + +#define PEEK_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \ + do { \ + if (cbuf_type == 0) { \ + c = cptr[-1]; \ + } else { \ + const uint16_t *_p = (const uint16_t *)cptr - 1; \ + const uint16_t *_start = (const uint16_t *)cbuf_start; \ + c = *_p; \ + if (is_lo_surrogate(c)) \ + if (cbuf_type == 2) \ + if (_p > _start) \ + if (is_hi_surrogate(_p[-1])) \ + c = from_surrogate(*--_p, c); \ + } \ + } while (0) + +#define GET_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \ + do { \ + if (cbuf_type == 0) { \ + cptr--; \ + c = cptr[0]; \ + } else { \ + const uint16_t *_p = (const uint16_t *)cptr - 1; \ + const uint16_t *_start = (const uint16_t *)cbuf_start; \ + c = *_p; \ + if (is_lo_surrogate(c)) \ + if (cbuf_type == 2) \ + if (_p > _start) \ + if (is_hi_surrogate(_p[-1])) \ + c = from_surrogate(*--_p, c); \ + cptr = (const void *)_p; \ + } \ + } while (0) + +#define PREV_CHAR(cptr, cbuf_start, cbuf_type) \ + do { \ + if (cbuf_type == 0) { \ + cptr--; \ + } else { \ + const uint16_t *_p = (const uint16_t *)cptr - 1; \ + const uint16_t *_start = (const uint16_t *)cbuf_start; \ + if (is_lo_surrogate(*_p)) \ + if (cbuf_type == 2) \ + if (_p > _start) \ + if (is_hi_surrogate(_p[-1])) \ + _p--; \ + cptr = (const void *)_p; \ + } \ + } while (0) + +typedef uintptr_t StackInt; + +typedef enum { + RE_EXEC_STATE_SPLIT, + RE_EXEC_STATE_LOOKAHEAD, + RE_EXEC_STATE_NEGATIVE_LOOKAHEAD, + RE_EXEC_STATE_GREEDY_QUANT, +} REExecStateEnum; + +typedef struct REExecState { + REExecStateEnum type : 8; + uint8_t stack_len; + size_t count; /* only used for RE_EXEC_STATE_GREEDY_QUANT */ + const uint8_t *cptr; + const uint8_t *pc; + void *buf[]; +} REExecState; + +typedef struct { + const uint8_t *cbuf; + const uint8_t *cbuf_end; + /* 0 = 8 bit chars, 1 = 16 bit chars, 2 = 16 bit chars, UTF-16 */ + int cbuf_type; + int capture_count; + int stack_size_max; + bool multi_line; + bool ignore_case; + bool is_unicode; + int interrupt_counter; + void *opaque; /* used for stack overflow check */ + + size_t state_size; + uint8_t *state_stack; + size_t state_stack_size; + size_t state_stack_len; +} REExecContext; + +static int push_state(REExecContext *s, + uint8_t **capture, + StackInt *stack, size_t stack_len, + const uint8_t *pc, const uint8_t *cptr, + REExecStateEnum type, size_t count) +{ + REExecState *rs; + uint8_t *new_stack; + size_t new_size, i, n; + StackInt *stack_buf; + + if (unlikely((s->state_stack_len + 1) > s->state_stack_size)) { + /* reallocate the stack */ + new_size = s->state_stack_size * 3 / 2; + if (new_size < 8) + new_size = 8; + new_stack = lre_realloc(s->opaque, s->state_stack, new_size * s->state_size); + if (!new_stack) + return -1; + s->state_stack_size = new_size; + s->state_stack = new_stack; + } + rs = (REExecState *)(s->state_stack + s->state_stack_len * s->state_size); + s->state_stack_len++; + rs->type = type; + rs->count = count; + rs->stack_len = stack_len; + rs->cptr = cptr; + rs->pc = pc; + n = 2 * s->capture_count; + for(i = 0; i < n; i++) + rs->buf[i] = capture[i]; + stack_buf = (StackInt *)(rs->buf + n); + for(i = 0; i < stack_len; i++) + stack_buf[i] = stack[i]; + return 0; +} + +static int lre_poll_timeout(REExecContext *s) +{ + if (unlikely(--s->interrupt_counter <= 0)) { + s->interrupt_counter = INTERRUPT_COUNTER_INIT; + if (lre_check_timeout(s->opaque)) + return LRE_RET_TIMEOUT; + } + return 0; +} + +/* return 1 if match, 0 if not match or < 0 if error. */ +static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, + StackInt *stack, int stack_len, + const uint8_t *pc, const uint8_t *cptr, + bool no_recurse) +{ + int opcode, ret; + int cbuf_type; + uint32_t val, c; + const uint8_t *cbuf_end; + + cbuf_type = s->cbuf_type; + cbuf_end = s->cbuf_end; + + for(;;) { + // printf("top=%p: pc=%d\n", th_list.top, (int)(pc - (bc_buf + RE_HEADER_LEN))); + opcode = *pc++; + switch(opcode) { + case REOP_match: + { + REExecState *rs; + if (no_recurse) + return (intptr_t)cptr; + ret = 1; + goto recurse; + no_match: + if (no_recurse) + return 0; + ret = 0; + recurse: + for(;;) { + if (lre_poll_timeout(s)) + return LRE_RET_TIMEOUT; + if (s->state_stack_len == 0) + return ret; + rs = (REExecState *)(s->state_stack + + (s->state_stack_len - 1) * s->state_size); + if (rs->type == RE_EXEC_STATE_SPLIT) { + if (!ret) { + pop_state: + memcpy(capture, rs->buf, + sizeof(capture[0]) * 2 * s->capture_count); + pop_state1: + pc = rs->pc; + cptr = rs->cptr; + stack_len = rs->stack_len; + memcpy(stack, rs->buf + 2 * s->capture_count, + stack_len * sizeof(stack[0])); + s->state_stack_len--; + break; + } + } else if (rs->type == RE_EXEC_STATE_GREEDY_QUANT) { + if (!ret) { + uint32_t char_count, i; + memcpy(capture, rs->buf, + sizeof(capture[0]) * 2 * s->capture_count); + stack_len = rs->stack_len; + memcpy(stack, rs->buf + 2 * s->capture_count, + stack_len * sizeof(stack[0])); + pc = rs->pc; + cptr = rs->cptr; + /* go backward */ + char_count = get_u32(pc + 12); + for(i = 0; i < char_count; i++) { + PREV_CHAR(cptr, s->cbuf, cbuf_type); + } + pc = (pc + 16) + (int)get_u32(pc); + rs->cptr = cptr; + rs->count--; + if (rs->count == 0) { + s->state_stack_len--; + } + break; + } + } else { + ret = ((rs->type == RE_EXEC_STATE_LOOKAHEAD && ret) || + (rs->type == RE_EXEC_STATE_NEGATIVE_LOOKAHEAD && !ret)); + if (ret) { + /* keep the capture in case of positive lookahead */ + if (rs->type == RE_EXEC_STATE_LOOKAHEAD) + goto pop_state1; + else + goto pop_state; + } + } + s->state_stack_len--; + } + } + break; + case REOP_char32: + val = get_u32(pc); + pc += 4; + goto test_char; + case REOP_char16: + val = get_u16(pc); + pc += 2; + goto test_char; + case REOP_char8: + val = get_u8(pc); + pc += 1; + test_char: + if (cptr >= cbuf_end) + goto no_match; + GET_CHAR(c, cptr, cbuf_end, cbuf_type); + if (s->ignore_case) { + c = lre_canonicalize(c, s->is_unicode); + } + if (val != c) + goto no_match; + break; + case REOP_split_goto_first: + case REOP_split_next_first: + { + const uint8_t *pc1; + + val = get_u32(pc); + pc += 4; + if (opcode == REOP_split_next_first) { + pc1 = pc + (int)val; + } else { + pc1 = pc; + pc = pc + (int)val; + } + ret = push_state(s, capture, stack, stack_len, + pc1, cptr, RE_EXEC_STATE_SPLIT, 0); + if (ret < 0) + return LRE_RET_MEMORY_ERROR; + break; + } + case REOP_lookahead: + case REOP_negative_lookahead: + val = get_u32(pc); + pc += 4; + ret = push_state(s, capture, stack, stack_len, + pc + (int)val, cptr, + RE_EXEC_STATE_LOOKAHEAD + opcode - REOP_lookahead, + 0); + if (ret < 0) + return LRE_RET_MEMORY_ERROR; + break; + + case REOP_goto: + val = get_u32(pc); + pc += 4 + (int)val; + if (lre_poll_timeout(s)) + return LRE_RET_TIMEOUT; + break; + case REOP_line_start: + if (cptr == s->cbuf) + break; + if (!s->multi_line) + goto no_match; + PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type); + if (!is_line_terminator(c)) + goto no_match; + break; + case REOP_line_end: + if (cptr == cbuf_end) + break; + if (!s->multi_line) + goto no_match; + PEEK_CHAR(c, cptr, cbuf_end, cbuf_type); + if (!is_line_terminator(c)) + goto no_match; + break; + case REOP_dot: + if (cptr == cbuf_end) + goto no_match; + GET_CHAR(c, cptr, cbuf_end, cbuf_type); + if (is_line_terminator(c)) + goto no_match; + break; + case REOP_any: + if (cptr == cbuf_end) + goto no_match; + GET_CHAR(c, cptr, cbuf_end, cbuf_type); + break; + case REOP_save_start: + case REOP_save_end: + val = *pc++; + assert(val < s->capture_count); + capture[2 * val + opcode - REOP_save_start] = (uint8_t *)cptr; + break; + case REOP_save_reset: + { + uint32_t val2; + val = pc[0]; + val2 = pc[1]; + pc += 2; + assert(val2 < s->capture_count); + while (val <= val2) { + capture[2 * val] = NULL; + capture[2 * val + 1] = NULL; + val++; + } + } + break; + case REOP_push_i32: + val = get_u32(pc); + pc += 4; + stack[stack_len++] = val; + break; + case REOP_drop: + stack_len--; + break; + case REOP_loop: + val = get_u32(pc); + pc += 4; + if (--stack[stack_len - 1] != 0) { + pc += (int)val; + if (lre_poll_timeout(s)) + return LRE_RET_TIMEOUT; + } + break; + case REOP_push_char_pos: + stack[stack_len++] = (uintptr_t)cptr; + break; + case REOP_check_advance: + if (stack[--stack_len] == (uintptr_t)cptr) + goto no_match; + break; + case REOP_word_boundary: + case REOP_not_word_boundary: + { + bool v1, v2; + /* char before */ + if (cptr == s->cbuf) { + v1 = false; + } else { + PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type); + v1 = is_word_char(c); + } + /* current char */ + if (cptr >= cbuf_end) { + v2 = false; + } else { + PEEK_CHAR(c, cptr, cbuf_end, cbuf_type); + v2 = is_word_char(c); + } + if (v1 ^ v2 ^ (REOP_not_word_boundary - opcode)) + goto no_match; + } + break; + case REOP_back_reference: + case REOP_backward_back_reference: + { + const uint8_t *cptr1, *cptr1_end, *cptr1_start; + uint32_t c1, c2; + + val = *pc++; + if (val >= s->capture_count) + goto no_match; + cptr1_start = capture[2 * val]; + cptr1_end = capture[2 * val + 1]; + if (!cptr1_start || !cptr1_end) + break; + if (opcode == REOP_back_reference) { + cptr1 = cptr1_start; + while (cptr1 < cptr1_end) { + if (cptr >= cbuf_end) + goto no_match; + GET_CHAR(c1, cptr1, cptr1_end, cbuf_type); + GET_CHAR(c2, cptr, cbuf_end, cbuf_type); + if (s->ignore_case) { + c1 = lre_canonicalize(c1, s->is_unicode); + c2 = lre_canonicalize(c2, s->is_unicode); + } + if (c1 != c2) + goto no_match; + } + } else { + cptr1 = cptr1_end; + while (cptr1 > cptr1_start) { + if (cptr == s->cbuf) + goto no_match; + GET_PREV_CHAR(c1, cptr1, cptr1_start, cbuf_type); + GET_PREV_CHAR(c2, cptr, s->cbuf, cbuf_type); + if (s->ignore_case) { + c1 = lre_canonicalize(c1, s->is_unicode); + c2 = lre_canonicalize(c2, s->is_unicode); + } + if (c1 != c2) + goto no_match; + } + } + } + break; + case REOP_range: + { + int n; + uint32_t low, high, idx_min, idx_max, idx; + + n = get_u16(pc); /* n must be >= 1 */ + pc += 2; + if (cptr >= cbuf_end) + goto no_match; + GET_CHAR(c, cptr, cbuf_end, cbuf_type); + if (s->ignore_case) { + c = lre_canonicalize(c, s->is_unicode); + } + idx_min = 0; + low = get_u16(pc + 0 * 4); + if (c < low) + goto no_match; + idx_max = n - 1; + high = get_u16(pc + idx_max * 4 + 2); + /* 0xffff in for last value means +infinity */ + if (unlikely(c >= 0xffff) && high == 0xffff) + goto range_match; + if (c > high) + goto no_match; + while (idx_min <= idx_max) { + idx = (idx_min + idx_max) / 2; + low = get_u16(pc + idx * 4); + high = get_u16(pc + idx * 4 + 2); + if (c < low) + idx_max = idx - 1; + else if (c > high) + idx_min = idx + 1; + else + goto range_match; + } + goto no_match; + range_match: + pc += 4 * n; + } + break; + case REOP_range32: + { + int n; + uint32_t low, high, idx_min, idx_max, idx; + + n = get_u16(pc); /* n must be >= 1 */ + pc += 2; + if (cptr >= cbuf_end) + goto no_match; + GET_CHAR(c, cptr, cbuf_end, cbuf_type); + if (s->ignore_case) { + c = lre_canonicalize(c, s->is_unicode); + } + idx_min = 0; + low = get_u32(pc + 0 * 8); + if (c < low) + goto no_match; + idx_max = n - 1; + high = get_u32(pc + idx_max * 8 + 4); + if (c > high) + goto no_match; + while (idx_min <= idx_max) { + idx = (idx_min + idx_max) / 2; + low = get_u32(pc + idx * 8); + high = get_u32(pc + idx * 8 + 4); + if (c < low) + idx_max = idx - 1; + else if (c > high) + idx_min = idx + 1; + else + goto range32_match; + } + goto no_match; + range32_match: + pc += 8 * n; + } + break; + case REOP_prev: + /* go to the previous char */ + if (cptr == s->cbuf) + goto no_match; + PREV_CHAR(cptr, s->cbuf, cbuf_type); + break; + case REOP_simple_greedy_quant: + { + uint32_t next_pos, quant_min, quant_max; + size_t q; + intptr_t res; + const uint8_t *pc1; + + next_pos = get_u32(pc); + quant_min = get_u32(pc + 4); + quant_max = get_u32(pc + 8); + pc += 16; + pc1 = pc; + pc += (int)next_pos; + + q = 0; + for(;;) { + if (lre_poll_timeout(s)) + return LRE_RET_TIMEOUT; + res = lre_exec_backtrack(s, capture, stack, stack_len, + pc1, cptr, true); + if (res == LRE_RET_MEMORY_ERROR || + res == LRE_RET_TIMEOUT) + return res; + if (!res) + break; + cptr = (uint8_t *)res; + q++; + if (q >= quant_max && quant_max != INT32_MAX) + break; + } + if (q < quant_min) + goto no_match; + if (q > quant_min) { + /* will examine all matches down to quant_min */ + ret = push_state(s, capture, stack, stack_len, + pc1 - 16, cptr, + RE_EXEC_STATE_GREEDY_QUANT, + q - quant_min); + if (ret < 0) + return LRE_RET_MEMORY_ERROR; + } + } + break; + default: + abort(); + } + } +} + +/* Return 1 if match, 0 if not match or < 0 if error (see LRE_RET_x). cindex is the + starting position of the match and must be such as 0 <= cindex <= + clen. */ +int lre_exec(uint8_t **capture, + const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen, + int cbuf_type, void *opaque) +{ + REExecContext s_s, *s = &s_s; + int re_flags, i, alloca_size, ret; + StackInt *stack_buf; + + re_flags = lre_get_flags(bc_buf); + s->multi_line = (re_flags & LRE_FLAG_MULTILINE) != 0; + s->ignore_case = (re_flags & LRE_FLAG_IGNORECASE) != 0; + s->is_unicode = (re_flags & LRE_FLAG_UNICODE) != 0; + s->capture_count = bc_buf[RE_HEADER_CAPTURE_COUNT]; + s->stack_size_max = bc_buf[RE_HEADER_STACK_SIZE]; + s->cbuf = cbuf; + s->cbuf_end = cbuf + (clen << cbuf_type); + s->cbuf_type = cbuf_type; + if (s->cbuf_type == 1 && s->is_unicode) + s->cbuf_type = 2; + s->interrupt_counter = INTERRUPT_COUNTER_INIT; + s->opaque = opaque; + + s->state_size = sizeof(REExecState) + + s->capture_count * sizeof(capture[0]) * 2 + + s->stack_size_max * sizeof(stack_buf[0]); + s->state_stack = NULL; + s->state_stack_len = 0; + s->state_stack_size = 0; + + for(i = 0; i < s->capture_count * 2; i++) + capture[i] = NULL; + alloca_size = s->stack_size_max * sizeof(stack_buf[0]); + stack_buf = alloca(alloca_size); + ret = lre_exec_backtrack(s, capture, stack_buf, 0, bc_buf + RE_HEADER_LEN, + cbuf + (cindex << cbuf_type), false); + lre_realloc(s->opaque, s->state_stack, 0); + return ret; +} + +int lre_get_capture_count(const uint8_t *bc_buf) +{ + return bc_buf[RE_HEADER_CAPTURE_COUNT]; +} + +int lre_get_flags(const uint8_t *bc_buf) +{ + return get_u16(bc_buf + RE_HEADER_FLAGS); +} + +/* Return NULL if no group names. Otherwise, return a pointer to + 'capture_count - 1' zero terminated UTF-8 strings. */ +const char *lre_get_groupnames(const uint8_t *bc_buf) +{ + uint32_t re_bytecode_len; + if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0) + return NULL; + re_bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN); + return (const char *)(bc_buf + RE_HEADER_LEN + re_bytecode_len); +} + +void lre_byte_swap(uint8_t *buf, size_t len, bool is_byte_swapped) +{ + uint8_t *p, *pe; + uint32_t n, r, nw; + + p = buf; + if (len < RE_HEADER_LEN) + abort(); + + // format is: + //
+ // + // + // + // etc. + inplace_bswap16(&p[RE_HEADER_FLAGS]); + + n = get_u32(&p[RE_HEADER_BYTECODE_LEN]); + inplace_bswap32(&p[RE_HEADER_BYTECODE_LEN]); + if (is_byte_swapped) + n = bswap32(n); + if (n > len - RE_HEADER_LEN) + abort(); + + p = &buf[RE_HEADER_LEN]; + pe = &p[n]; + + while (p < pe) { + n = reopcode_info[*p].size; + switch (n) { + case 1: + case 2: + break; + case 3: + switch (*p) { + case REOP_save_reset: // has two 8 bit arguments + break; + case REOP_range32: // variable length + nw = get_u16(&p[1]); // number of pairs of uint32_t + if (is_byte_swapped) + n = bswap16(n); + for (r = 3 + 8 * nw; n < r; n += 4) + inplace_bswap32(&p[n]); + goto doswap16; + case REOP_range: // variable length + nw = get_u16(&p[1]); // number of pairs of uint16_t + if (is_byte_swapped) + n = bswap16(n); + for (r = 3 + 4 * nw; n < r; n += 2) + inplace_bswap16(&p[n]); + goto doswap16; + default: + doswap16: + inplace_bswap16(&p[1]); + break; + } + break; + case 5: + inplace_bswap32(&p[1]); + break; + case 17: + assert(*p == REOP_simple_greedy_quant); + inplace_bswap32(&p[1]); + inplace_bswap32(&p[5]); + inplace_bswap32(&p[9]); + inplace_bswap32(&p[13]); + break; + default: + abort(); + } + p = &p[n]; + } +} + +#ifdef TEST + +bool lre_check_stack_overflow(void *opaque, size_t alloca_size) +{ + return false; +} + +void *lre_realloc(void *opaque, void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +int main(int argc, char **argv) +{ + int len, flags, ret, i; + uint8_t *bc; + char error_msg[64]; + uint8_t *capture[CAPTURE_COUNT_MAX * 2]; + const char *input; + int input_len, capture_count; + + if (argc < 4) { + printf("usage: %s regexp flags input\n", argv[0]); + exit(1); + } + flags = atoi(argv[2]); + bc = lre_compile(&len, error_msg, sizeof(error_msg), argv[1], + strlen(argv[1]), flags, NULL); + if (!bc) { + fprintf(stderr, "error: %s\n", error_msg); + exit(1); + } + + input = argv[3]; + input_len = strlen(input); + + ret = lre_exec(capture, bc, (uint8_t *)input, 0, input_len, 0, NULL); + printf("ret=%d\n", ret); + if (ret == 1) { + capture_count = lre_get_capture_count(bc); + for(i = 0; i < 2 * capture_count; i++) { + uint8_t *ptr; + ptr = capture[i]; + printf("%d: ", i); + if (!ptr) + printf(""); + else + printf("%u", (int)(ptr - (uint8_t *)input)); + printf("\n"); + } + } + return 0; +} +#endif diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/libregexp.h b/host/cred-script/vendor/rquickjs-sys/quickjs/libregexp.h new file mode 100644 index 0000000..898e9a7 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/libregexp.h @@ -0,0 +1,97 @@ +/* + * Regular Expression Engine + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef LIBREGEXP_H +#define LIBREGEXP_H + +#include +#include + +#include "libunicode.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LRE_FLAG_GLOBAL (1 << 0) +#define LRE_FLAG_IGNORECASE (1 << 1) +#define LRE_FLAG_MULTILINE (1 << 2) +#define LRE_FLAG_DOTALL (1 << 3) +#define LRE_FLAG_UNICODE (1 << 4) +#define LRE_FLAG_STICKY (1 << 5) +#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */ +#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ +#define LRE_FLAG_UNICODE_SETS (1 << 8) + +#define LRE_RET_MEMORY_ERROR (-1) +#define LRE_RET_TIMEOUT (-2) + +uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, + const char *buf, size_t buf_len, int re_flags, + void *opaque); +int lre_get_capture_count(const uint8_t *bc_buf); +int lre_get_flags(const uint8_t *bc_buf); +const char *lre_get_groupnames(const uint8_t *bc_buf); +int lre_exec(uint8_t **capture, + const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen, + int cbuf_type, void *opaque); + +int lre_parse_escape(const uint8_t **pp, int allow_utf16); +bool lre_is_space(int c); + +void lre_byte_swap(uint8_t *buf, size_t len, bool is_byte_swapped); + +/* must be provided by the user */ +bool lre_check_stack_overflow(void *opaque, size_t alloca_size); +/* must be provided by the user, return non zero if time out */ +int lre_check_timeout(void *opaque); +void *lre_realloc(void *opaque, void *ptr, size_t size); + +/* JS identifier test */ +extern uint32_t const lre_id_start_table_ascii[4]; +extern uint32_t const lre_id_continue_table_ascii[4]; + +static inline int lre_js_is_ident_first(int c) +{ + if ((uint32_t)c < 128) { + return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1; + } else { + return lre_is_id_start(c); + } +} + +static inline int lre_js_is_ident_next(int c) +{ + if ((uint32_t)c < 128) { + return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1; + } else { + /* ZWNJ and ZWJ are accepted in identifiers */ + return lre_is_id_continue(c) || c == 0x200C || c == 0x200D; + } +} + +#ifdef __cplusplus +} /* extern "C" { */ +#endif + +#endif /* LIBREGEXP_H */ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/libunicode-table.h b/host/cred-script/vendor/rquickjs-sys/quickjs/libunicode-table.h new file mode 100644 index 0000000..c75e9e3 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/libunicode-table.h @@ -0,0 +1,4707 @@ +/* Compressed unicode tables */ +/* Automatically generated file - do not edit */ + +#include + +static const uint32_t case_conv_table1[378] = { + 0x00209a30, 0x00309a00, 0x005a8173, 0x00601730, + 0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700, + 0x007f8100, 0x00803040, 0x009801c3, 0x00988190, + 0x00990640, 0x009c9040, 0x00a481b4, 0x00a52e40, + 0x00bc0130, 0x00bc8640, 0x00bf8170, 0x00c00100, + 0x00c08130, 0x00c10440, 0x00c30130, 0x00c38240, + 0x00c48230, 0x00c58240, 0x00c70130, 0x00c78130, + 0x00c80130, 0x00c88240, 0x00c98130, 0x00ca0130, + 0x00ca8100, 0x00cb0130, 0x00cb8130, 0x00cc0240, + 0x00cd0100, 0x00cd8101, 0x00ce0130, 0x00ce8130, + 0x00cf0100, 0x00cf8130, 0x00d00640, 0x00d30130, + 0x00d38240, 0x00d48130, 0x00d60240, 0x00d70130, + 0x00d78240, 0x00d88230, 0x00d98440, 0x00db8130, + 0x00dc0240, 0x00de0240, 0x00df8100, 0x00e20350, + 0x00e38350, 0x00e50350, 0x00e69040, 0x00ee8100, + 0x00ef1240, 0x00f801b4, 0x00f88350, 0x00fa0240, + 0x00fb0130, 0x00fb8130, 0x00fc2840, 0x01100130, + 0x01111240, 0x011d0131, 0x011d8240, 0x011e8130, + 0x011f0131, 0x011f8201, 0x01208240, 0x01218130, + 0x01220130, 0x01228130, 0x01230a40, 0x01280101, + 0x01288101, 0x01290101, 0x01298100, 0x012a0100, + 0x012b0200, 0x012c8100, 0x012d8100, 0x012e0101, + 0x01300100, 0x01308101, 0x01318100, 0x01320101, + 0x01328101, 0x01330101, 0x01340100, 0x01348100, + 0x01350101, 0x01358101, 0x01360101, 0x01378100, + 0x01388101, 0x01390100, 0x013a8100, 0x013e8101, + 0x01400100, 0x01410101, 0x01418100, 0x01438101, + 0x01440100, 0x01448100, 0x01450200, 0x01460100, + 0x01490100, 0x014e8101, 0x014f0101, 0x01a28173, + 0x01b80440, 0x01bb0240, 0x01bd8300, 0x01bf8130, + 0x01c30130, 0x01c40330, 0x01c60130, 0x01c70230, + 0x01c801d0, 0x01c89130, 0x01d18930, 0x01d60100, + 0x01d68300, 0x01d801d3, 0x01d89100, 0x01e10173, + 0x01e18900, 0x01e60100, 0x01e68200, 0x01e78130, + 0x01e80173, 0x01e88173, 0x01ea8173, 0x01eb0173, + 0x01eb8100, 0x01ec1840, 0x01f80173, 0x01f88173, + 0x01f90100, 0x01f98100, 0x01fa01a0, 0x01fa8173, + 0x01fb8240, 0x01fc8130, 0x01fd0240, 0x01fe8330, + 0x02001030, 0x02082030, 0x02182000, 0x02281000, + 0x02302240, 0x02453640, 0x02600130, 0x02608e40, + 0x02678100, 0x02686040, 0x0298a630, 0x02b0a600, + 0x02c381b5, 0x08502631, 0x08638131, 0x08668131, + 0x08682b00, 0x087e8300, 0x09d05011, 0x09f80610, + 0x09fc0620, 0x0e400174, 0x0e408174, 0x0e410174, + 0x0e418174, 0x0e420174, 0x0e428174, 0x0e430174, + 0x0e438180, 0x0e440180, 0x0e448240, 0x0e482b30, + 0x0e5e8330, 0x0ebc8101, 0x0ebe8101, 0x0ec70101, + 0x0f007e40, 0x0f3f1840, 0x0f4b01b5, 0x0f4b81b6, + 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7, 0x0f4d8180, + 0x0f4f0130, 0x0f506040, 0x0f800800, 0x0f840830, + 0x0f880600, 0x0f8c0630, 0x0f900800, 0x0f940830, + 0x0f980800, 0x0f9c0830, 0x0fa00600, 0x0fa40630, + 0x0fa801b0, 0x0fa88100, 0x0fa901d3, 0x0fa98100, + 0x0faa01d3, 0x0faa8100, 0x0fab01d3, 0x0fab8100, + 0x0fac8130, 0x0fad8130, 0x0fae8130, 0x0faf8130, + 0x0fb00800, 0x0fb40830, 0x0fb80200, 0x0fb90400, + 0x0fbb0201, 0x0fbc0201, 0x0fbd0201, 0x0fbe0201, + 0x0fc008b7, 0x0fc40867, 0x0fc808b8, 0x0fcc0868, + 0x0fd008b8, 0x0fd40868, 0x0fd80200, 0x0fd901b9, + 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1, 0x0fdb81d7, + 0x0fdc0230, 0x0fdd0230, 0x0fde0161, 0x0fdf0173, + 0x0fe101b9, 0x0fe181b2, 0x0fe201ba, 0x0fe301b2, + 0x0fe381d8, 0x0fe40430, 0x0fe60162, 0x0fe80201, + 0x0fe901d0, 0x0fe981d0, 0x0feb01b0, 0x0feb81d0, + 0x0fec0230, 0x0fed0230, 0x0ff00201, 0x0ff101d3, + 0x0ff181d3, 0x0ff201ba, 0x0ff28101, 0x0ff301b0, + 0x0ff381d3, 0x0ff40231, 0x0ff50230, 0x0ff60131, + 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb, 0x0ffb01b2, + 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230, 0x0ffe0162, + 0x109301a0, 0x109501a0, 0x109581a0, 0x10990131, + 0x10a70101, 0x10b01031, 0x10b81001, 0x10c18240, + 0x125b1a31, 0x12681a01, 0x16003031, 0x16183001, + 0x16300240, 0x16310130, 0x16318130, 0x16320130, + 0x16328100, 0x16330100, 0x16338640, 0x16368130, + 0x16370130, 0x16378130, 0x16380130, 0x16390240, + 0x163a8240, 0x163f0230, 0x16406440, 0x16758440, + 0x16790240, 0x16802600, 0x16938100, 0x16968100, + 0x53202e40, 0x53401c40, 0x53910e40, 0x53993e40, + 0x53bc8440, 0x53be8130, 0x53bf0a40, 0x53c58240, + 0x53c68130, 0x53c80440, 0x53ca0101, 0x53cb1440, + 0x53d50130, 0x53d58130, 0x53d60130, 0x53d68130, + 0x53d70130, 0x53d80130, 0x53d88130, 0x53d90130, + 0x53d98131, 0x53da1040, 0x53e20131, 0x53e28130, + 0x53e30130, 0x53e38440, 0x53e58130, 0x53e61040, + 0x53ee0130, 0x53fa8240, 0x55a98101, 0x55b85020, + 0x7d8001b2, 0x7d8081b2, 0x7d8101b2, 0x7d8181da, + 0x7d8201da, 0x7d8281b3, 0x7d8301b3, 0x7d8981bb, + 0x7d8a01bb, 0x7d8a81bb, 0x7d8b01bc, 0x7d8b81bb, + 0x7f909a31, 0x7fa09a01, 0x82002831, 0x82142801, + 0x82582431, 0x826c2401, 0x82b80b31, 0x82be0f31, + 0x82c60731, 0x82ca0231, 0x82cb8b01, 0x82d18f01, + 0x82d98701, 0x82dd8201, 0x86403331, 0x86603301, + 0x86a81631, 0x86b81601, 0x8c502031, 0x8c602001, + 0xb7202031, 0xb7302001, 0xb7501931, 0xb75d9901, + 0xf4802231, 0xf4912201, +}; + +static const uint8_t case_conv_table2[378] = { + 0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04, + 0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00, + 0x08, 0x00, 0x53, 0x4b, 0x52, 0x00, 0x53, 0x00, + 0x54, 0x00, 0x3b, 0x55, 0x56, 0x00, 0x58, 0x5a, + 0x40, 0x5f, 0x5e, 0x00, 0x47, 0x50, 0x63, 0x65, + 0x43, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, 0x6c, + 0x00, 0x6e, 0x00, 0x70, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00, + 0x20, 0x36, 0x00, 0x28, 0x00, 0x24, 0x00, 0x24, + 0x25, 0x2d, 0x00, 0x13, 0x6d, 0x6f, 0x00, 0x29, + 0x27, 0x2a, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x41, + 0x1e, 0x42, 0x1f, 0x4e, 0x3c, 0x40, 0x22, 0x21, + 0x44, 0x21, 0x43, 0x26, 0x28, 0x27, 0x29, 0x23, + 0x2b, 0x4b, 0x2d, 0x46, 0x2f, 0x4c, 0x31, 0x4d, + 0x33, 0x47, 0x45, 0x99, 0x00, 0x00, 0x97, 0x91, + 0x7f, 0x80, 0x85, 0x86, 0x12, 0x82, 0x84, 0x78, + 0x79, 0x12, 0x7d, 0xa3, 0x7e, 0x7a, 0x7b, 0x8c, + 0x92, 0x98, 0xa6, 0xa0, 0x87, 0x00, 0x9a, 0xa1, + 0x95, 0x77, 0x33, 0x95, 0x00, 0x90, 0x00, 0x76, + 0x9b, 0x9a, 0x99, 0x98, 0x00, 0x00, 0xa0, 0x00, + 0x9e, 0x00, 0xa3, 0xa2, 0x15, 0x31, 0x32, 0x33, + 0xb7, 0xb8, 0x53, 0xac, 0xab, 0x12, 0x14, 0x1e, + 0x21, 0x22, 0x22, 0x2a, 0x34, 0x35, 0x00, 0xa8, + 0xa9, 0x39, 0x22, 0x4c, 0x00, 0x00, 0x97, 0x01, + 0x5a, 0xda, 0x1d, 0x36, 0x05, 0x00, 0xc7, 0xc6, + 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce, + 0xc4, 0xd8, 0x45, 0xd9, 0x42, 0xda, 0x46, 0xdb, + 0xd1, 0xd3, 0xd5, 0xd7, 0xdd, 0xdc, 0xf1, 0xf9, + 0x01, 0x11, 0x0a, 0x12, 0x80, 0x9f, 0x00, 0x21, + 0x80, 0xa3, 0xf0, 0x00, 0xc0, 0x40, 0xc6, 0x60, + 0xea, 0xde, 0xe6, 0x99, 0xc0, 0x00, 0x00, 0x06, + 0x60, 0xdf, 0x29, 0x00, 0x15, 0x12, 0x06, 0x16, + 0xfb, 0xe0, 0x09, 0x15, 0x12, 0x84, 0x0b, 0xc6, + 0x16, 0x02, 0xe2, 0x06, 0xc0, 0x40, 0x00, 0x46, + 0x60, 0xe1, 0xe3, 0x6d, 0x37, 0x38, 0x39, 0x18, + 0x17, 0x1a, 0x19, 0x00, 0x1d, 0x1c, 0x1f, 0x1e, + 0x00, 0x61, 0xba, 0x67, 0x45, 0x48, 0x00, 0x50, + 0x64, 0x4f, 0x51, 0x00, 0x00, 0x49, 0x00, 0x00, + 0x00, 0xa5, 0xa6, 0xa7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb9, 0x00, 0x00, 0x5c, 0x00, 0x4a, 0x00, + 0x5d, 0x57, 0x59, 0x62, 0x60, 0x72, 0x6b, 0x71, + 0x52, 0x00, 0x3e, 0x69, 0xbb, 0x00, 0x5b, 0x00, + 0x25, 0x00, 0x48, 0xaa, 0x8a, 0x8b, 0x8c, 0xab, + 0xac, 0x58, 0x58, 0xaf, 0x94, 0xb0, 0x6f, 0xb2, + 0x61, 0x60, 0x63, 0x62, 0x65, 0x64, 0x6a, 0x6b, + 0x6c, 0x6d, 0x66, 0x67, 0x68, 0x69, 0x6f, 0x6e, + 0x71, 0x70, 0x73, 0x72, 0x75, 0x74, 0x77, 0x76, + 0x79, 0x78, +}; + +static const uint16_t case_conv_ext[58] = { + 0x0399, 0x0308, 0x0301, 0x03a5, 0x0313, 0x0300, 0x0342, 0x0391, + 0x0397, 0x03a9, 0x0046, 0x0049, 0x004c, 0x0053, 0x0069, 0x0307, + 0x02bc, 0x004e, 0x004a, 0x030c, 0x0535, 0x0552, 0x0048, 0x0331, + 0x0054, 0x0057, 0x030a, 0x0059, 0x0041, 0x02be, 0x1f08, 0x1f80, + 0x1f28, 0x1f90, 0x1f68, 0x1fa0, 0x1fba, 0x0386, 0x1fb3, 0x1fca, + 0x0389, 0x1fc3, 0x03a1, 0x1ffa, 0x038f, 0x1ff3, 0x0544, 0x0546, + 0x053b, 0x054e, 0x053d, 0x03b8, 0x0462, 0xa64a, 0x1e60, 0x03c9, + 0x006b, 0x00e5, +}; + +static const uint8_t unicode_prop_Cased1_table[190] = { + 0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3, + 0x80, 0x9b, 0x81, 0x8d, 0x02, 0x80, 0xe1, 0x80, + 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, 0x11, 0x03, + 0x04, 0x08, 0x01, 0x08, 0x30, 0x08, 0x01, 0x15, + 0x20, 0x01, 0x31, 0x99, 0x31, 0x9d, 0x84, 0x40, + 0x94, 0x80, 0xd6, 0x82, 0xa6, 0x80, 0x41, 0x62, + 0x80, 0xa6, 0x80, 0x4b, 0x72, 0x80, 0x4c, 0x02, + 0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb, + 0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f, + 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28, + 0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b, + 0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79, + 0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94, + 0x05, 0x80, 0x98, 0x80, 0xc0, 0x1a, 0x82, 0x43, + 0x34, 0xa2, 0x06, 0x80, 0x8d, 0x60, 0x5c, 0x15, + 0x01, 0x10, 0xa9, 0x80, 0x88, 0x60, 0xcc, 0x44, + 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, + 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, + 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, + 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, + 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, + 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x47, 0x33, + 0x89, 0x80, 0x93, 0x2d, 0x41, 0x04, 0xbd, 0x50, + 0xc1, 0x99, 0x85, 0x99, 0x85, 0x99, +}; + +static const uint8_t unicode_prop_Cased1_index[18] = { + 0xb9, 0x02, 0x80, 0xa0, 0x1e, 0x40, 0x9e, 0xa6, + 0x40, 0x55, 0xd4, 0x21, 0x15, 0xd7, 0x21, 0x8a, + 0xf1, 0x01, +}; + +static const uint8_t unicode_prop_Case_Ignorable_table[785] = { + 0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80, + 0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6, + 0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40, + 0xfa, 0x86, 0x40, 0xce, 0x04, 0x80, 0xb0, 0xac, + 0x00, 0x01, 0x01, 0x00, 0xab, 0x80, 0x8a, 0x85, + 0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f, + 0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80, + 0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08, + 0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0c, 0x88, + 0xa8, 0xb9, 0xb6, 0x00, 0x03, 0x3b, 0x02, 0x86, + 0x89, 0x81, 0x8c, 0x80, 0x8e, 0x80, 0xb9, 0x03, + 0x1f, 0x80, 0x93, 0x81, 0x99, 0x01, 0x81, 0xb8, + 0x03, 0x0b, 0x09, 0x12, 0x80, 0x9d, 0x0a, 0x80, + 0x8a, 0x81, 0xb8, 0x03, 0x20, 0x0b, 0x80, 0x93, + 0x81, 0x95, 0x28, 0x80, 0xb9, 0x01, 0x00, 0x1f, + 0x06, 0x81, 0x8a, 0x81, 0x9d, 0x80, 0xbc, 0x80, + 0x8b, 0x80, 0xb1, 0x02, 0x80, 0xb6, 0x00, 0x14, + 0x10, 0x1e, 0x81, 0x8a, 0x81, 0x9c, 0x80, 0xb9, + 0x01, 0x05, 0x04, 0x81, 0x93, 0x81, 0x9b, 0x81, + 0xb8, 0x0b, 0x1f, 0x80, 0x93, 0x81, 0x9c, 0x80, + 0xc7, 0x06, 0x10, 0x80, 0xd9, 0x01, 0x86, 0x8a, + 0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x86, 0xc8, + 0x81, 0x9a, 0x00, 0x00, 0x80, 0xb6, 0x8d, 0x04, + 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe5, + 0x18, 0x28, 0x09, 0x81, 0x98, 0x0b, 0x82, 0x8f, + 0x83, 0x8c, 0x01, 0x0d, 0x80, 0x8e, 0x80, 0xdd, + 0x80, 0x42, 0x5f, 0x82, 0x43, 0xb1, 0x82, 0x9c, + 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xbf, 0x08, 0x37, + 0x01, 0x8a, 0x10, 0x20, 0xac, 0x84, 0xb2, 0x80, + 0xc0, 0x81, 0xa1, 0x80, 0xf5, 0x13, 0x81, 0x88, + 0x05, 0x82, 0x40, 0xda, 0x09, 0x80, 0xb9, 0x00, + 0x30, 0x00, 0x01, 0x3d, 0x89, 0x08, 0xa6, 0x07, + 0xad, 0x81, 0x8b, 0x93, 0x83, 0xaf, 0x00, 0x20, + 0x04, 0x80, 0xa7, 0x88, 0x8b, 0x81, 0x9f, 0x19, + 0x08, 0x82, 0xb7, 0x00, 0x0a, 0x00, 0x82, 0xb9, + 0x39, 0x81, 0xbf, 0x85, 0xd1, 0x10, 0x8c, 0x06, + 0x18, 0x28, 0x11, 0xb1, 0xbe, 0x8c, 0x80, 0xa1, + 0xe4, 0x41, 0xbc, 0x00, 0x82, 0x8a, 0x82, 0x8c, + 0x82, 0x8c, 0x82, 0x8c, 0x81, 0x8b, 0x27, 0x81, + 0x89, 0x01, 0x01, 0x84, 0xb0, 0x20, 0x89, 0x00, + 0x8c, 0x80, 0x8f, 0x8c, 0xb2, 0xa0, 0x4b, 0x8a, + 0x81, 0xf0, 0x82, 0xfc, 0x80, 0x8e, 0x80, 0xdf, + 0x9f, 0xae, 0x80, 0x41, 0xd4, 0x80, 0xa3, 0x1a, + 0x24, 0x80, 0xdc, 0x85, 0xdc, 0x82, 0x60, 0x6f, + 0x15, 0x80, 0x44, 0xe1, 0x85, 0x41, 0x0d, 0x80, + 0xe1, 0x18, 0x89, 0x00, 0x9b, 0x83, 0xcf, 0x81, + 0x8d, 0xa1, 0xcd, 0x80, 0x96, 0x82, 0xe5, 0x1a, + 0x0f, 0x02, 0x03, 0x80, 0x98, 0x0c, 0x80, 0x40, + 0x96, 0x81, 0x99, 0x91, 0x8c, 0x80, 0xa5, 0x87, + 0x98, 0x8a, 0xad, 0x82, 0xaf, 0x01, 0x19, 0x81, + 0x90, 0x80, 0x94, 0x81, 0xc1, 0x29, 0x09, 0x81, + 0x8b, 0x07, 0x80, 0xa2, 0x80, 0x8a, 0x80, 0xb2, + 0x00, 0x11, 0x0c, 0x08, 0x80, 0x9a, 0x80, 0x8d, + 0x0c, 0x08, 0x80, 0xe3, 0x84, 0x88, 0x82, 0xf8, + 0x01, 0x03, 0x80, 0x60, 0x4f, 0x2f, 0x80, 0x40, + 0x92, 0x90, 0x42, 0x3c, 0x8f, 0x10, 0x8b, 0x8f, + 0xa1, 0x01, 0x80, 0x40, 0xa8, 0x06, 0x05, 0x80, + 0x8a, 0x80, 0xa2, 0x00, 0x80, 0xae, 0x80, 0xac, + 0x81, 0xc2, 0x80, 0x94, 0x82, 0x42, 0x00, 0x80, + 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x44, 0x04, + 0x28, 0xa9, 0x80, 0x88, 0x42, 0x45, 0x10, 0x0c, + 0x83, 0xa7, 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, + 0x3c, 0x83, 0xa5, 0x80, 0x99, 0x20, 0x80, 0x41, + 0x3a, 0x81, 0x97, 0x80, 0xb3, 0x85, 0xc5, 0x8a, + 0xb0, 0x83, 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, + 0x81, 0x89, 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, + 0x89, 0x80, 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, + 0x80, 0x8b, 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, + 0xde, 0x11, 0x00, 0x0d, 0x01, 0x80, 0x40, 0x9c, + 0x02, 0x87, 0x94, 0x81, 0xb8, 0x0a, 0x80, 0xa4, + 0x32, 0x84, 0xc5, 0x85, 0x8c, 0x00, 0x00, 0x80, + 0x8d, 0x81, 0xd4, 0x39, 0x10, 0x80, 0x96, 0x80, + 0xd3, 0x28, 0x03, 0x08, 0x81, 0x40, 0xed, 0x1d, + 0x08, 0x81, 0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81, + 0xe9, 0x00, 0x01, 0x28, 0x80, 0xe4, 0x00, 0x01, + 0x18, 0x84, 0x41, 0x02, 0x88, 0x01, 0x40, 0xff, + 0x08, 0x03, 0x80, 0x40, 0x8f, 0x19, 0x0b, 0x80, + 0x9f, 0x89, 0xa7, 0x29, 0x1f, 0x80, 0x88, 0x29, + 0x82, 0xad, 0x8c, 0x01, 0x40, 0xc5, 0x00, 0x10, + 0x80, 0x40, 0xc8, 0x30, 0x28, 0x80, 0xd1, 0x95, + 0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30, + 0x80, 0xc7, 0x0a, 0x00, 0x80, 0xc0, 0x80, 0x41, + 0x18, 0x81, 0x8a, 0x81, 0xb3, 0x24, 0x00, 0x80, + 0x96, 0x80, 0x54, 0xd4, 0x90, 0x85, 0x8e, 0x60, + 0x2c, 0xc7, 0x8b, 0x12, 0x49, 0xbf, 0x84, 0xba, + 0x86, 0x88, 0x83, 0x41, 0xfb, 0x82, 0xa7, 0x81, + 0x41, 0xe1, 0x80, 0xbe, 0x90, 0xbf, 0x08, 0x81, + 0x8c, 0x81, 0x60, 0x3f, 0xfb, 0x18, 0x30, 0x81, + 0x4c, 0x9d, 0x08, 0x83, 0x52, 0x5b, 0xad, 0x81, + 0x96, 0x42, 0x1f, 0x82, 0x88, 0x8f, 0x0e, 0x9d, + 0x83, 0x40, 0x93, 0x82, 0x47, 0xba, 0xb6, 0x83, + 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45, + 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x84, 0xbd, + 0xa0, 0x80, 0x40, 0x9f, 0x8d, 0x41, 0x6f, 0x80, + 0xbc, 0x83, 0x41, 0xfa, 0x84, 0x40, 0xfd, 0x81, + 0x40, 0xf2, 0x01, 0x06, 0x0c, 0x80, 0x88, 0x80, + 0x41, 0xcf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84, + 0x6c, 0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40, + 0xef, +}; + +static const uint8_t unicode_prop_Case_Ignorable_index[75] = { + 0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a, + 0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f, + 0x10, 0x80, 0xd4, 0x17, 0x40, 0xde, 0x1a, 0x20, + 0xe9, 0x1c, 0x00, 0x72, 0x20, 0x00, 0x16, 0xa0, + 0x40, 0xc6, 0xa8, 0x40, 0xc2, 0xaa, 0xa0, 0x30, + 0xfe, 0x00, 0xb1, 0x07, 0x41, 0x51, 0x0f, 0x01, + 0xd0, 0x11, 0x01, 0x5f, 0x14, 0x01, 0x44, 0x19, + 0x61, 0xa8, 0x1c, 0x01, 0x2a, 0x61, 0x61, 0xff, + 0xaf, 0x01, 0x19, 0xe0, 0x61, 0x00, 0xe7, 0x01, + 0xf0, 0x01, 0x0e, +}; + +static const uint8_t unicode_prop_ID_Start_table[1146] = { + 0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03, + 0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83, + 0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20, + 0x09, 0x18, 0x05, 0x00, 0x10, 0x00, 0x93, 0x80, + 0xd2, 0x80, 0x40, 0x8a, 0x87, 0x40, 0xa5, 0x80, + 0xa5, 0x08, 0x85, 0xa8, 0xc6, 0x9a, 0x1b, 0xac, + 0xaa, 0xa2, 0x08, 0xe2, 0x00, 0x8e, 0x0e, 0x81, + 0x89, 0x11, 0x80, 0x8f, 0x00, 0x9d, 0x9c, 0xd8, + 0x8a, 0x80, 0x97, 0xa0, 0x88, 0x0b, 0x04, 0x95, + 0x18, 0x88, 0x02, 0x80, 0x96, 0x98, 0x86, 0x8a, + 0x84, 0x97, 0x06, 0x8f, 0xa9, 0xb9, 0xb5, 0x10, + 0x91, 0x06, 0x89, 0x8e, 0x8f, 0x1f, 0x09, 0x81, + 0x95, 0x06, 0x00, 0x13, 0x10, 0x8f, 0x80, 0x8c, + 0x08, 0x82, 0x8d, 0x81, 0x89, 0x07, 0x2b, 0x09, + 0x95, 0x06, 0x01, 0x01, 0x01, 0x9e, 0x18, 0x80, + 0x92, 0x82, 0x8f, 0x88, 0x02, 0x80, 0x95, 0x06, + 0x01, 0x04, 0x10, 0x91, 0x80, 0x8e, 0x81, 0x96, + 0x80, 0x8a, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, + 0x10, 0x9d, 0x08, 0x82, 0x8e, 0x80, 0x90, 0x00, + 0x2a, 0x10, 0x1a, 0x08, 0x00, 0x0a, 0x0a, 0x12, + 0x8b, 0x95, 0x80, 0xb3, 0x38, 0x10, 0x96, 0x80, + 0x8f, 0x10, 0x99, 0x10, 0x09, 0x81, 0x9d, 0x03, + 0x38, 0x10, 0x96, 0x80, 0x89, 0x04, 0x10, 0x9d, + 0x10, 0x81, 0x8e, 0x81, 0x90, 0x88, 0x02, 0x80, + 0xa8, 0x08, 0x8f, 0x04, 0x17, 0x82, 0x97, 0x2c, + 0x91, 0x82, 0x97, 0x80, 0x88, 0x00, 0x0e, 0xb9, + 0xaf, 0x01, 0x8b, 0x86, 0xb9, 0x08, 0x00, 0x20, + 0x97, 0x00, 0x80, 0x89, 0x01, 0x88, 0x01, 0x20, + 0x80, 0x94, 0x83, 0x9f, 0x80, 0xbe, 0x38, 0xa3, + 0x9a, 0x84, 0xf2, 0xaa, 0x93, 0x80, 0x8f, 0x2b, + 0x1a, 0x02, 0x0e, 0x13, 0x8c, 0x8b, 0x80, 0x90, + 0xa5, 0x00, 0x20, 0x81, 0xaa, 0x80, 0x41, 0x4c, + 0x03, 0x0e, 0x00, 0x03, 0x81, 0xa8, 0x03, 0x81, + 0xa0, 0x03, 0x0e, 0x00, 0x03, 0x81, 0x8e, 0x80, + 0xb8, 0x03, 0x81, 0xc2, 0xa4, 0x8f, 0x8f, 0xd5, + 0x0d, 0x82, 0x42, 0x6b, 0x81, 0x90, 0x80, 0x99, + 0x84, 0xca, 0x82, 0x8a, 0x86, 0x91, 0x8c, 0x92, + 0x8d, 0x91, 0x8d, 0x8c, 0x02, 0x8e, 0xb3, 0xa2, + 0x03, 0x80, 0xc2, 0xd8, 0x86, 0xa8, 0x00, 0x84, + 0xc5, 0x89, 0x9e, 0xb0, 0x9d, 0x0c, 0x8a, 0xab, + 0x83, 0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80, + 0xdc, 0xae, 0x90, 0x87, 0xb5, 0x9d, 0x8c, 0x81, + 0x89, 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3, + 0x81, 0x8a, 0x84, 0xaa, 0x0a, 0xa8, 0x18, 0x28, + 0x0a, 0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d, + 0x81, 0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80, + 0x9e, 0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13, + 0x0d, 0x83, 0x8c, 0x22, 0x06, 0xf3, 0x80, 0x8c, + 0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, + 0x0d, 0x28, 0x00, 0x00, 0x80, 0x8f, 0x0b, 0x24, + 0x18, 0x90, 0xa8, 0x4a, 0x76, 0x40, 0xe4, 0x2b, + 0x11, 0x8b, 0xa5, 0x00, 0x20, 0x81, 0xb7, 0x30, + 0x8f, 0x96, 0x88, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x86, 0x42, 0x25, 0x82, 0x98, 0x88, + 0x34, 0x0c, 0x83, 0xd5, 0x1c, 0x80, 0xd9, 0x03, + 0x84, 0xaa, 0x80, 0xdd, 0x90, 0x9f, 0xaf, 0x8f, + 0x41, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x56, 0x8c, + 0xc2, 0xad, 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89, + 0x81, 0x93, 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6, + 0x88, 0x81, 0xe6, 0x81, 0xd1, 0x93, 0x90, 0x02, + 0x03, 0x80, 0x96, 0x9c, 0xb3, 0x8d, 0xb1, 0xbd, + 0x2a, 0x00, 0x81, 0x8a, 0x9b, 0x89, 0x96, 0x98, + 0x9c, 0x86, 0xae, 0x9b, 0x80, 0x8f, 0x20, 0x89, + 0x89, 0x20, 0xa8, 0x96, 0x10, 0x87, 0x93, 0x96, + 0x10, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08, 0x00, + 0x97, 0x11, 0x8a, 0x32, 0x8b, 0x29, 0x29, 0x85, + 0x88, 0x30, 0x30, 0xaa, 0x80, 0x8d, 0x85, 0xf2, + 0x9c, 0x60, 0x2b, 0xa3, 0x8b, 0x96, 0x83, 0xb0, + 0x60, 0x21, 0x03, 0x41, 0x6d, 0x81, 0xe9, 0xa5, + 0x86, 0x8b, 0x24, 0x00, 0x89, 0x80, 0x8c, 0x04, + 0x00, 0x01, 0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a, + 0x91, 0xbf, 0x81, 0xb5, 0xa7, 0x8b, 0xf3, 0x20, + 0x40, 0x86, 0xa3, 0x99, 0x85, 0x99, 0x8a, 0xd8, + 0x15, 0x0d, 0x0d, 0x0a, 0xa2, 0x8b, 0x80, 0x99, + 0x80, 0x92, 0x01, 0x80, 0x8e, 0x81, 0x8d, 0xa1, + 0xfa, 0xc4, 0xb4, 0x41, 0x0a, 0x9c, 0x82, 0xb0, + 0xae, 0x9f, 0x8c, 0x9d, 0x84, 0xa5, 0x89, 0x9d, + 0x81, 0xa3, 0x1f, 0x04, 0xa9, 0x40, 0x9d, 0x91, + 0xa3, 0x83, 0xa3, 0x83, 0xa7, 0x87, 0xb3, 0x8b, + 0x8a, 0x80, 0x8e, 0x06, 0x01, 0x80, 0x8a, 0x80, + 0x8e, 0x06, 0x01, 0x82, 0xb3, 0x8b, 0x41, 0x36, + 0x88, 0x95, 0x89, 0x87, 0x97, 0x28, 0xa9, 0x80, + 0x88, 0xc4, 0x29, 0x00, 0xab, 0x01, 0x10, 0x81, + 0x96, 0x89, 0x96, 0x88, 0x9e, 0xc0, 0x92, 0x01, + 0x89, 0x95, 0x89, 0x99, 0x85, 0x99, 0xa5, 0xb7, + 0x29, 0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c, 0xa9, + 0x9c, 0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a, 0xb5, + 0x89, 0x95, 0x89, 0x92, 0x8c, 0x91, 0xed, 0xc8, + 0xb6, 0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0xa5, 0x9b, + 0x88, 0x96, 0x40, 0xf9, 0xa9, 0x29, 0x8f, 0x85, + 0xb7, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91, 0xad, + 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09, 0x80, + 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c, 0x01, + 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83, 0x94, + 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0x92, 0x81, + 0xbe, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, 0x86, + 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, + 0x10, 0x91, 0x80, 0x8b, 0x84, 0x9d, 0x89, 0x00, + 0x08, 0x80, 0xa5, 0x00, 0x98, 0x00, 0x80, 0xab, + 0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93, + 0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3, + 0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6, + 0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf, + 0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e, 0x00, + 0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b, + 0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad, + 0x92, 0x80, 0x91, 0xc8, 0x40, 0xc6, 0xa0, 0x9e, + 0x88, 0x80, 0xa4, 0x90, 0x80, 0xb0, 0x9d, 0xef, + 0x30, 0x08, 0xa5, 0x94, 0x80, 0x98, 0x28, 0x08, + 0x9f, 0x8d, 0x80, 0x96, 0xab, 0x41, 0x03, 0x92, + 0x8e, 0x00, 0x8c, 0x80, 0xa1, 0xfb, 0x80, 0xce, + 0x43, 0x99, 0xe5, 0xee, 0x90, 0x40, 0xc3, 0x4a, + 0x4b, 0xe0, 0x8e, 0x44, 0x2f, 0x90, 0x85, 0x98, + 0x4f, 0x9a, 0x84, 0x42, 0x46, 0x5a, 0xb8, 0x9d, + 0x46, 0xe1, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce, + 0x90, 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94, + 0x84, 0x92, 0x41, 0xaf, 0xac, 0x40, 0xd2, 0xbf, + 0x9f, 0x98, 0x81, 0x98, 0xab, 0xca, 0x20, 0xc1, + 0x8c, 0xbf, 0x08, 0x80, 0x8d, 0x84, 0x88, 0x5c, + 0xd5, 0xa8, 0x9f, 0xe0, 0xf2, 0x60, 0x21, 0xfc, + 0x18, 0x30, 0x08, 0x41, 0x22, 0x8e, 0x80, 0x9c, + 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b, 0x49, 0x03, + 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86, 0x89, 0x57, + 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, + 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, + 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, + 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x47, + 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd, 0x40, 0x91, + 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40, 0x9d, + 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x40, 0xe3, 0x9d, + 0x08, 0x40, 0xce, 0x9e, 0x02, 0x01, 0x06, 0x0c, + 0x88, 0x81, 0x40, 0xdf, 0x30, 0x18, 0x08, 0x8e, + 0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44, 0xb3, + 0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, 0x03, + 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02, 0x01, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89, 0x80, + 0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43, 0x60, + 0xa6, 0xdf, 0x9f, 0x51, 0x1d, 0x81, 0x56, 0x8d, + 0x81, 0x5d, 0x30, 0x8e, 0x42, 0x6d, 0x49, 0xa1, + 0x42, 0x1d, 0x45, 0xe1, 0x53, 0x4a, 0x84, 0x60, + 0x21, 0x29, +}; + +static const uint8_t unicode_prop_ID_Start_index[108] = { + 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09, + 0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b, + 0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00, + 0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d, + 0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00, + 0x32, 0x00, 0x06, 0xa8, 0x00, 0x77, 0xaa, 0x00, + 0xfc, 0xd7, 0x00, 0xfd, 0xfe, 0x40, 0xd1, 0x02, + 0x01, 0xb2, 0x05, 0x21, 0xf6, 0x08, 0x01, 0x49, + 0x0c, 0x01, 0x76, 0x10, 0x01, 0xdf, 0x12, 0x21, + 0xc8, 0x14, 0x41, 0x42, 0x19, 0x21, 0x31, 0x1d, + 0x61, 0xf1, 0x2f, 0x41, 0x78, 0x6b, 0x01, 0x23, + 0xb1, 0xa1, 0xad, 0xd4, 0x01, 0x6f, 0xd7, 0x01, + 0xee, 0xe5, 0x01, 0x38, 0xee, 0x01, 0xe0, 0xa6, + 0x42, 0x7a, 0x34, 0x03, +}; + +static const uint8_t unicode_prop_ID_Continue1_table[708] = { + 0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47, + 0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08, + 0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, + 0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89, + 0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89, + 0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02, + 0x04, 0xaa, 0x82, 0xba, 0x88, 0xa9, 0x97, 0x80, + 0xa0, 0xb5, 0x10, 0x91, 0x06, 0x89, 0x09, 0x89, + 0x90, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88, + 0x80, 0x89, 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7, + 0x00, 0x23, 0x09, 0x12, 0x80, 0x93, 0x8b, 0x10, + 0x8a, 0x82, 0xb7, 0x00, 0x38, 0x10, 0x82, 0x93, + 0x09, 0x89, 0x89, 0x28, 0x82, 0xb7, 0x00, 0x31, + 0x09, 0x16, 0x82, 0x89, 0x09, 0x89, 0x91, 0x80, + 0xba, 0x22, 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89, + 0x8f, 0x84, 0xb6, 0x00, 0x30, 0x10, 0x1e, 0x81, + 0x8a, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x30, + 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x10, 0x8b, + 0x83, 0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80, + 0x89, 0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28, + 0x00, 0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b, + 0x38, 0x89, 0xd6, 0x01, 0x88, 0x8a, 0x30, 0x89, + 0xbd, 0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81, + 0xb0, 0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, + 0x80, 0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10, + 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42, + 0xbe, 0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b, + 0x82, 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88, + 0x01, 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80, + 0xf5, 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a, + 0xbb, 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a, + 0x85, 0x89, 0x95, 0x8d, 0x80, 0x9e, 0x81, 0x8b, + 0x93, 0x84, 0xae, 0x90, 0x8a, 0x89, 0x90, 0x88, + 0x8b, 0x82, 0x9d, 0x8c, 0x81, 0x89, 0xab, 0x8d, + 0xaf, 0x93, 0x87, 0x89, 0x85, 0x89, 0xf5, 0x10, + 0x94, 0x18, 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42, + 0x0b, 0x81, 0xb0, 0x81, 0x92, 0x80, 0xfa, 0x8c, + 0x18, 0x82, 0x8b, 0x4b, 0xfd, 0x82, 0x40, 0x8c, + 0x80, 0xdf, 0x9f, 0x42, 0x29, 0x85, 0xe8, 0x81, + 0xdf, 0x80, 0x60, 0x75, 0x23, 0x89, 0xc4, 0x03, + 0x89, 0x9f, 0x81, 0xcf, 0x81, 0x41, 0x0f, 0x02, + 0x03, 0x80, 0x96, 0x23, 0x80, 0xd2, 0x81, 0xb1, + 0x91, 0x89, 0x89, 0x85, 0x91, 0x8c, 0x8a, 0x9b, + 0x87, 0x98, 0x8c, 0xab, 0x83, 0xae, 0x8d, 0x8e, + 0x89, 0x8a, 0x80, 0x89, 0x89, 0xae, 0x8d, 0x8b, + 0x07, 0x09, 0x89, 0xa0, 0x82, 0xb1, 0x00, 0x11, + 0x0c, 0x08, 0x80, 0xa8, 0x24, 0x81, 0x40, 0xeb, + 0x38, 0x09, 0x89, 0x60, 0x4f, 0x23, 0x80, 0x42, + 0xe0, 0x8f, 0x8f, 0x8f, 0x11, 0x97, 0x82, 0x40, + 0xbf, 0x89, 0xa4, 0x80, 0xa4, 0x80, 0x42, 0x96, + 0x80, 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, + 0x24, 0x89, 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, + 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, + 0x89, 0x85, 0x89, 0x9e, 0x84, 0x41, 0x3c, 0x81, + 0xcc, 0x85, 0xc5, 0x8a, 0xb0, 0x83, 0xf9, 0x82, + 0xb4, 0x8e, 0x9e, 0x8a, 0x09, 0x89, 0x83, 0xac, + 0x8a, 0x30, 0xac, 0x89, 0x2a, 0xa3, 0x8d, 0x80, + 0x89, 0x21, 0xab, 0x80, 0x8b, 0x82, 0xaf, 0x8d, + 0x3b, 0x80, 0x8b, 0xd1, 0x8b, 0x28, 0x08, 0x40, + 0x9c, 0x8b, 0x84, 0x89, 0x2b, 0xb6, 0x08, 0x31, + 0x09, 0x82, 0x88, 0x80, 0x89, 0x09, 0x32, 0x84, + 0xc2, 0x88, 0x00, 0x08, 0x03, 0x04, 0x00, 0x8d, + 0x81, 0xd1, 0x91, 0x88, 0x89, 0x18, 0xd0, 0x93, + 0x8b, 0x89, 0x40, 0xd4, 0x31, 0x88, 0x9a, 0x81, + 0xd1, 0x90, 0x8e, 0x89, 0xd0, 0x8c, 0x87, 0x89, + 0x85, 0x93, 0xb8, 0x8e, 0x83, 0x89, 0x40, 0xf1, + 0x8e, 0x40, 0xa4, 0x89, 0xc5, 0x28, 0x09, 0x18, + 0x00, 0x81, 0x8b, 0x89, 0xf6, 0x31, 0x32, 0x80, + 0x9b, 0x89, 0xa7, 0x30, 0x1f, 0x80, 0x88, 0x8a, + 0xad, 0x8f, 0x40, 0xc5, 0x87, 0x40, 0x87, 0x89, + 0xb4, 0x38, 0x87, 0x8f, 0x89, 0xb7, 0x95, 0x80, + 0x8d, 0xf9, 0x2a, 0x00, 0x08, 0x30, 0x07, 0x89, + 0xaf, 0x20, 0x08, 0x27, 0x89, 0xb5, 0x89, 0x41, + 0x08, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32, 0x84, + 0x8c, 0x8a, 0x54, 0xe4, 0x05, 0x8e, 0x60, 0x2c, + 0xc7, 0x9b, 0x49, 0x25, 0x89, 0xd5, 0x89, 0xa5, + 0x84, 0xba, 0x86, 0x98, 0x89, 0x42, 0x15, 0x89, + 0x41, 0xd4, 0x00, 0xb6, 0x33, 0xd0, 0x80, 0x8a, + 0x81, 0x60, 0x4c, 0xaa, 0x81, 0x50, 0x50, 0x89, + 0x42, 0x05, 0xad, 0x81, 0x96, 0x42, 0x1d, 0x22, + 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40, 0x93, 0x82, + 0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6, 0x83, 0xb1, + 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45, 0x4f, + 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, 0x80, 0x40, + 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80, 0xbc, + 0x8d, 0x41, 0xf1, 0x8d, 0x40, 0xf3, 0x08, 0x89, + 0x40, 0xe7, 0x01, 0x06, 0x0c, 0x80, 0x41, 0xd9, + 0x86, 0xec, 0x34, 0x89, 0x52, 0x95, 0x89, 0x6c, + 0x05, 0x05, 0x40, 0xef, +}; + +static const uint8_t unicode_prop_ID_Continue1_index[66] = { + 0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a, + 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x60, 0xc7, + 0x0f, 0x20, 0xea, 0x17, 0x40, 0xec, 0x1a, 0x00, + 0x0e, 0x20, 0x40, 0x7e, 0xa6, 0x20, 0xda, 0xa9, + 0x20, 0x10, 0xfe, 0x40, 0x40, 0x0a, 0x41, 0xbb, + 0x10, 0x21, 0x4e, 0x13, 0x41, 0xde, 0x15, 0x01, + 0xe5, 0x19, 0x01, 0x5a, 0x1d, 0x01, 0xf5, 0x6a, + 0x21, 0x8c, 0xd1, 0x61, 0x37, 0xe1, 0x41, 0xf0, + 0x01, 0x0e, +}; + +static const uint8_t unicode_prop_White_Space_table[22] = { + 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80, + 0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c, + 0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80, +}; + +static const uint8_t unicode_prop_White_Space_index[3] = { + 0x01, 0x30, 0x00, +}; + +static const uint8_t unicode_cc_table[937] = { + 0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00, + 0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03, + 0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03, + 0xdc, 0xc7, 0x00, 0xf0, 0xc0, 0x02, 0xdc, 0xc2, + 0x01, 0xdc, 0x80, 0xc2, 0x03, 0xdc, 0xc0, 0x00, + 0xe8, 0x01, 0xdc, 0xc0, 0x41, 0xe9, 0x00, 0xea, + 0x41, 0xe9, 0x00, 0xea, 0x00, 0xe9, 0xcc, 0xb0, + 0xe2, 0xc4, 0xb0, 0xd8, 0x00, 0xdc, 0xc3, 0x00, + 0xdc, 0xc2, 0x00, 0xde, 0x00, 0xdc, 0xc5, 0x05, + 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xde, 0x00, + 0xe4, 0xc0, 0x49, 0x0a, 0x43, 0x13, 0x80, 0x00, + 0x17, 0x80, 0x41, 0x18, 0x80, 0xc0, 0x00, 0xdc, + 0x80, 0x00, 0x12, 0xb0, 0x17, 0xc7, 0x42, 0x1e, + 0xaf, 0x47, 0x1b, 0xc1, 0x01, 0xdc, 0xc4, 0x00, + 0xdc, 0xc1, 0x00, 0xdc, 0x8f, 0x00, 0x23, 0xb0, + 0x34, 0xc6, 0x81, 0xc3, 0x00, 0xdc, 0xc0, 0x81, + 0xc1, 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xa2, + 0x00, 0x24, 0x9d, 0xc0, 0x00, 0xdc, 0xc1, 0x00, + 0xdc, 0xc1, 0x02, 0xdc, 0xc0, 0x01, 0xdc, 0xc0, + 0x00, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x00, 0xdc, + 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xc1, 0xb0, + 0x6f, 0xc6, 0x00, 0xdc, 0xc0, 0x88, 0x00, 0xdc, + 0x97, 0xc3, 0x80, 0xc8, 0x80, 0xc2, 0x80, 0xc4, + 0xaa, 0x02, 0xdc, 0xb0, 0x0a, 0xc1, 0x02, 0xdc, + 0xc3, 0xa9, 0xc4, 0x04, 0xdc, 0xcd, 0x80, 0x00, + 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc2, + 0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, 0xdc, 0xc1, + 0x01, 0xdc, 0xc4, 0xb0, 0x0b, 0x00, 0x07, 0x8f, + 0x00, 0x09, 0x82, 0xc0, 0x00, 0xdc, 0xc1, 0xb0, + 0x36, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xaf, 0xc0, + 0xb0, 0x0c, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, + 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3d, + 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x4e, 0x00, + 0x09, 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, + 0x86, 0x00, 0x54, 0x00, 0x5b, 0xb0, 0x34, 0x00, + 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3c, 0x01, 0x09, + 0x8f, 0x00, 0x09, 0xb0, 0x4b, 0x00, 0x09, 0xb0, + 0x3c, 0x01, 0x67, 0x00, 0x09, 0x8c, 0x03, 0x6b, + 0xb0, 0x3b, 0x01, 0x76, 0x00, 0x09, 0x8c, 0x03, + 0x7a, 0xb0, 0x1b, 0x01, 0xdc, 0x9a, 0x00, 0xdc, + 0x80, 0x00, 0xdc, 0x80, 0x00, 0xd8, 0xb0, 0x06, + 0x41, 0x81, 0x80, 0x00, 0x84, 0x84, 0x03, 0x82, + 0x81, 0x00, 0x82, 0x80, 0xc1, 0x00, 0x09, 0x80, + 0xc1, 0xb0, 0x0d, 0x00, 0xdc, 0xb0, 0x3f, 0x00, + 0x07, 0x80, 0x01, 0x09, 0xb0, 0x21, 0x00, 0xdc, + 0xb2, 0x9e, 0xc2, 0xb3, 0x83, 0x01, 0x09, 0x9d, + 0x00, 0x09, 0xb0, 0x6c, 0x00, 0x09, 0x89, 0xc0, + 0xb0, 0x9a, 0x00, 0xe4, 0xb0, 0x5e, 0x00, 0xde, + 0xc0, 0x00, 0xdc, 0xb0, 0xaa, 0xc0, 0x00, 0xdc, + 0xb0, 0x16, 0x00, 0x09, 0x93, 0xc7, 0x81, 0x00, + 0xdc, 0xaf, 0xc4, 0x05, 0xdc, 0xc1, 0x00, 0xdc, + 0x80, 0x01, 0xdc, 0xc1, 0x01, 0xdc, 0xc4, 0x00, + 0xdc, 0xd1, 0x00, 0xdc, 0x81, 0xc5, 0x00, 0xdc, + 0xc3, 0x00, 0xea, 0xb0, 0x17, 0x00, 0x07, 0x8e, + 0x00, 0x09, 0xa5, 0xc0, 0x00, 0xdc, 0xc6, 0xb0, + 0x05, 0x01, 0x09, 0xb0, 0x09, 0x00, 0x07, 0x8a, + 0x01, 0x09, 0xb0, 0x12, 0x00, 0x07, 0xb0, 0x67, + 0xc2, 0x41, 0x00, 0x04, 0xdc, 0xc1, 0x03, 0xdc, + 0xc0, 0x41, 0x00, 0x05, 0x01, 0x83, 0x00, 0xdc, + 0x85, 0xc0, 0x82, 0xc1, 0xb0, 0x95, 0xc1, 0x00, + 0xdc, 0xc6, 0x00, 0xdc, 0xc1, 0x00, 0xea, 0x00, + 0xd6, 0x00, 0xdc, 0x00, 0xca, 0xe4, 0x00, 0xe8, + 0x01, 0xe4, 0x00, 0xdc, 0x00, 0xda, 0xc0, 0x00, + 0xe9, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xb2, 0x9f, + 0xc1, 0x01, 0x01, 0xc3, 0x02, 0x01, 0xc1, 0x83, + 0xc0, 0x82, 0x01, 0x01, 0xc0, 0x00, 0xdc, 0xc0, + 0x01, 0x01, 0x03, 0xdc, 0xc0, 0xb8, 0x03, 0xcd, + 0xc2, 0xb0, 0x5c, 0x00, 0x09, 0xb0, 0x2f, 0xdf, + 0xb1, 0xf9, 0x00, 0xda, 0x00, 0xe4, 0x00, 0xe8, + 0x00, 0xde, 0x01, 0xe0, 0xb0, 0x38, 0x01, 0x08, + 0xb8, 0x6d, 0xa3, 0xc0, 0x83, 0xc9, 0x9f, 0xc1, + 0xb0, 0x1f, 0xc1, 0xb0, 0xe3, 0x00, 0x09, 0xa4, + 0x00, 0x09, 0xb0, 0x66, 0x00, 0x09, 0x9a, 0xd1, + 0xb0, 0x08, 0x02, 0xdc, 0xa4, 0x00, 0x09, 0xb0, + 0x2e, 0x00, 0x07, 0x8b, 0x00, 0x09, 0xb0, 0xbe, + 0xc0, 0x80, 0xc1, 0x00, 0xdc, 0x81, 0xc1, 0x84, + 0xc1, 0x80, 0xc0, 0xb0, 0x03, 0x00, 0x09, 0xb0, + 0xc5, 0x00, 0x09, 0xb8, 0x46, 0xff, 0x00, 0x1a, + 0xb2, 0xd0, 0xc6, 0x06, 0xdc, 0xc1, 0xb3, 0x9c, + 0x00, 0xdc, 0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64, + 0xc4, 0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, + 0xc0, 0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, + 0xb0, 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, + 0xb0, 0x10, 0xc4, 0xb1, 0x0c, 0xc1, 0xb0, 0x1c, + 0x01, 0xdc, 0x80, 0x02, 0xdc, 0xb0, 0x15, 0x01, + 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x03, 0xdc, 0xb0, + 0x00, 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xb0, + 0x8f, 0x00, 0x09, 0xa8, 0x00, 0x09, 0x8d, 0x00, + 0x09, 0xb0, 0x08, 0x00, 0x09, 0x00, 0x07, 0xb0, + 0x14, 0xc2, 0xaf, 0x01, 0x09, 0xb0, 0x0d, 0x00, + 0x07, 0xb0, 0x1b, 0x00, 0x09, 0x88, 0x00, 0x07, + 0xb0, 0x39, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x81, + 0x00, 0x07, 0x00, 0x09, 0xb0, 0x1f, 0x01, 0x07, + 0x8f, 0x00, 0x09, 0x97, 0xc6, 0x82, 0xc4, 0xb0, + 0x28, 0x02, 0x09, 0xb0, 0x40, 0x00, 0x09, 0x82, + 0x00, 0x07, 0x96, 0xc0, 0xb0, 0x32, 0x00, 0x09, + 0x00, 0x07, 0xb0, 0xca, 0x00, 0x09, 0x00, 0x07, + 0xb0, 0x4d, 0x00, 0x09, 0xb0, 0x45, 0x00, 0x09, + 0x00, 0x07, 0xb0, 0x42, 0x00, 0x09, 0xb0, 0xdc, + 0x00, 0x09, 0x00, 0x07, 0xb0, 0xd1, 0x01, 0x09, + 0x83, 0x00, 0x07, 0xb0, 0x6b, 0x00, 0x09, 0xb0, + 0x22, 0x00, 0x09, 0x91, 0x00, 0x09, 0xb0, 0x20, + 0x00, 0x09, 0xb1, 0x74, 0x00, 0x09, 0xb0, 0xd1, + 0x00, 0x07, 0x80, 0x01, 0x09, 0xb0, 0x20, 0x00, + 0x09, 0xb1, 0x78, 0x01, 0x09, 0xb8, 0x39, 0xbb, + 0x00, 0x09, 0xb8, 0x01, 0x8f, 0x04, 0x01, 0xb0, + 0x0a, 0xc6, 0xb4, 0x88, 0x01, 0x06, 0xb8, 0x44, + 0x7b, 0x00, 0x01, 0xb8, 0x0c, 0x95, 0x01, 0xd8, + 0x02, 0x01, 0x82, 0x00, 0xe2, 0x04, 0xd8, 0x87, + 0x07, 0xdc, 0x81, 0xc4, 0x01, 0xdc, 0x9d, 0xc3, + 0xb0, 0x63, 0xc2, 0xb8, 0x05, 0x8a, 0xc6, 0x80, + 0xd0, 0x81, 0xc6, 0x80, 0xc1, 0x80, 0xc4, 0xb0, + 0x33, 0xc0, 0xb0, 0x6f, 0xc6, 0xb1, 0x46, 0xc0, + 0xb0, 0x0c, 0xc3, 0xb1, 0xcb, 0x01, 0xe8, 0x00, + 0xdc, 0xc0, 0xb0, 0xcd, 0xc0, 0x00, 0xdc, 0xb0, + 0xc2, 0xc0, 0x81, 0xc0, 0x86, 0xc1, 0x84, 0xc0, + 0xb1, 0xa9, 0x06, 0xdc, 0xb0, 0x3c, 0xc5, 0x00, + 0x07, +}; + +static const uint8_t unicode_cc_index[90] = { + 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05, + 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c, + 0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00, + 0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10, + 0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xf2, + 0x1b, 0x00, 0xc3, 0x1d, 0x20, 0xd0, 0x20, 0x00, + 0x00, 0x2e, 0x00, 0x2c, 0xa8, 0x00, 0xbe, 0xaa, + 0x00, 0x76, 0x03, 0x01, 0xfa, 0x0e, 0x01, 0x80, + 0x10, 0x21, 0xe9, 0x12, 0x01, 0xc3, 0x14, 0x01, + 0x3f, 0x19, 0x01, 0x98, 0x1d, 0x21, 0x67, 0xd1, + 0x01, 0x8f, 0xe0, 0x21, 0xf6, 0xe6, 0x01, 0x4b, + 0xe9, 0x01, +}; + +static const uint32_t unicode_decomp_table1[709] = { + 0x00280081, 0x002a0097, 0x002a8081, 0x002bc097, + 0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097, + 0x002e4115, 0x002f0199, 0x00302016, 0x00400842, + 0x00448a42, 0x004a0442, 0x004c0096, 0x004c8117, + 0x004d0242, 0x004e4342, 0x004fc12f, 0x0050c342, + 0x005240bf, 0x00530342, 0x00550942, 0x005a0842, + 0x005e0096, 0x005e4342, 0x005fc081, 0x00680142, + 0x006bc142, 0x00710185, 0x0071c317, 0x00734844, + 0x00778344, 0x00798342, 0x007b02be, 0x007c4197, + 0x007d0142, 0x007e0444, 0x00800e42, 0x00878142, + 0x00898744, 0x00ac0483, 0x00b60317, 0x00b80283, + 0x00d00214, 0x00d10096, 0x00dd0080, 0x00de8097, + 0x00df8080, 0x00e10097, 0x00e1413e, 0x00e1c080, + 0x00e204be, 0x00ea83ae, 0x00f282ae, 0x00f401ad, + 0x00f4c12e, 0x00f54103, 0x00fc0303, 0x00fe4081, + 0x0100023e, 0x0101c0be, 0x010301be, 0x010640be, + 0x010e40be, 0x0114023e, 0x0115c0be, 0x011701be, + 0x011d8144, 0x01304144, 0x01340244, 0x01358144, + 0x01368344, 0x01388344, 0x013a8644, 0x013e0144, + 0x0161c085, 0x018882ae, 0x019d422f, 0x01b00184, + 0x01b4c084, 0x024a4084, 0x024c4084, 0x024d0084, + 0x0256042e, 0x0272c12e, 0x02770120, 0x0277c084, + 0x028cc084, 0x028d8084, 0x029641ae, 0x02978084, + 0x02d20084, 0x02d2c12e, 0x02d70120, 0x02e50084, + 0x02f281ae, 0x03120084, 0x03300084, 0x0331c122, + 0x0332812e, 0x035281ae, 0x03768084, 0x037701ae, + 0x038cc085, 0x03acc085, 0x03b7012f, 0x03c30081, + 0x03d0c084, 0x03d34084, 0x03d48084, 0x03d5c084, + 0x03d70084, 0x03da4084, 0x03dcc084, 0x03dd412e, + 0x03ddc085, 0x03de0084, 0x03de4085, 0x03e04084, + 0x03e4c084, 0x03e74084, 0x03e88084, 0x03e9c084, + 0x03eb0084, 0x03ee4084, 0x04098084, 0x043f0081, + 0x06c18484, 0x06c48084, 0x06cec184, 0x06d00120, + 0x06d0c084, 0x074b0383, 0x074cc41f, 0x074f1783, + 0x075e0081, 0x0766d283, 0x07801d44, 0x078e8942, + 0x07931844, 0x079f0d42, 0x07a58216, 0x07a68085, + 0x07a6c0be, 0x07a80d44, 0x07aea044, 0x07c00122, + 0x07c08344, 0x07c20122, 0x07c28344, 0x07c40122, + 0x07c48244, 0x07c60122, 0x07c68244, 0x07c8113e, + 0x07d08244, 0x07d20122, 0x07d28244, 0x07d40122, + 0x07d48344, 0x07d64c3e, 0x07dc4080, 0x07dc80be, + 0x07dcc080, 0x07dd00be, 0x07dd4080, 0x07dd80be, + 0x07ddc080, 0x07de00be, 0x07de4080, 0x07de80be, + 0x07dec080, 0x07df00be, 0x07df4080, 0x07e00820, + 0x07e40820, 0x07e80820, 0x07ec05be, 0x07eec080, + 0x07ef00be, 0x07ef4097, 0x07ef8080, 0x07efc117, + 0x07f0443e, 0x07f24080, 0x07f280be, 0x07f2c080, + 0x07f303be, 0x07f4c080, 0x07f582ae, 0x07f6c080, + 0x07f7433e, 0x07f8c080, 0x07f903ae, 0x07fac080, + 0x07fb013e, 0x07fb8102, 0x07fc83be, 0x07fe4080, + 0x07fe80be, 0x07fec080, 0x07ff00be, 0x07ff4080, + 0x07ff8097, 0x0800011e, 0x08008495, 0x08044081, + 0x0805c097, 0x08090081, 0x08094097, 0x08098099, + 0x080bc081, 0x080cc085, 0x080d00b1, 0x080d8085, + 0x080dc0b1, 0x080f0197, 0x0811c197, 0x0815c0b3, + 0x0817c081, 0x081c0595, 0x081ec081, 0x081f0215, + 0x0820051f, 0x08228583, 0x08254415, 0x082a0097, + 0x08400119, 0x08408081, 0x0840c0bf, 0x08414119, + 0x0841c081, 0x084240bf, 0x0842852d, 0x08454081, + 0x08458097, 0x08464295, 0x08480097, 0x08484099, + 0x08488097, 0x08490081, 0x08498080, 0x084a0081, + 0x084a8102, 0x084b0495, 0x084d421f, 0x084e4081, + 0x084ec099, 0x084f0283, 0x08514295, 0x08540119, + 0x0854809b, 0x0854c619, 0x0857c097, 0x08580081, + 0x08584097, 0x08588099, 0x0858c097, 0x08590081, + 0x08594097, 0x08598099, 0x0859c09b, 0x085a0097, + 0x085a4081, 0x085a8097, 0x085ac099, 0x085b0295, + 0x085c4097, 0x085c8099, 0x085cc097, 0x085d0081, + 0x085d4097, 0x085d8099, 0x085dc09b, 0x085e0097, + 0x085e4081, 0x085e8097, 0x085ec099, 0x085f0215, + 0x08624099, 0x0866813e, 0x086b80be, 0x087341be, + 0x088100be, 0x088240be, 0x088300be, 0x088901be, + 0x088b0085, 0x088b40b1, 0x088bc085, 0x088c00b1, + 0x089040be, 0x089100be, 0x0891c1be, 0x089801be, + 0x089b42be, 0x089d0144, 0x089e0144, 0x08a00144, + 0x08a10144, 0x08a20144, 0x08ab023e, 0x08b80244, + 0x08ba8220, 0x08ca411e, 0x0918049f, 0x091a4523, + 0x091cc097, 0x091d04a5, 0x091f452b, 0x0921c09b, + 0x092204a1, 0x09244525, 0x0926c099, 0x09270d25, + 0x092d8d1f, 0x09340d1f, 0x093a8081, 0x0a8300b3, + 0x0a9d0099, 0x0a9d4097, 0x0a9d8099, 0x0ab700be, + 0x0b1f0115, 0x0b5bc081, 0x0ba7c081, 0x0bbcc081, + 0x0bc004ad, 0x0bc244ad, 0x0bc484ad, 0x0bc6f383, + 0x0be0852d, 0x0be31d03, 0x0bf1882d, 0x0c000081, + 0x0c0d8283, 0x0c130b84, 0x0c194284, 0x0c1c0122, + 0x0c1cc122, 0x0c1d8122, 0x0c1e4122, 0x0c1f0122, + 0x0c250084, 0x0c26c123, 0x0c278084, 0x0c27c085, + 0x0c2b0b84, 0x0c314284, 0x0c340122, 0x0c34c122, + 0x0c358122, 0x0c364122, 0x0c370122, 0x0c3d0084, + 0x0c3dc220, 0x0c3f8084, 0x0c3fc085, 0x0c4c4a2d, + 0x0c51451f, 0x0c53ca9f, 0x0c5915ad, 0x0c648703, + 0x0c800741, 0x0c838089, 0x0c83c129, 0x0c8441a9, + 0x0c850089, 0x0c854129, 0x0c85c2a9, 0x0c870089, + 0x0c87408f, 0x0c87808d, 0x0c881241, 0x0c910203, + 0x0c940099, 0x0c9444a3, 0x0c968323, 0x0c98072d, + 0x0c9b84af, 0x0c9dc2a1, 0x0c9f00b5, 0x0c9f40b3, + 0x0c9f8085, 0x0ca01883, 0x0cac4223, 0x0cad4523, + 0x0cafc097, 0x0cb004a1, 0x0cb241a5, 0x0cb30097, + 0x0cb34099, 0x0cb38097, 0x0cb3c099, 0x0cb417ad, + 0x0cbfc085, 0x0cc001b3, 0x0cc0c0b1, 0x0cc100b3, + 0x0cc14131, 0x0cc1c0b5, 0x0cc200b3, 0x0cc241b1, + 0x0cc30133, 0x0cc38131, 0x0cc40085, 0x0cc440b1, + 0x0cc48133, 0x0cc50085, 0x0cc540b5, 0x0cc580b7, + 0x0cc5c0b5, 0x0cc600b1, 0x0cc64135, 0x0cc6c0b3, + 0x0cc701b1, 0x0cc7c0b3, 0x0cc800b5, 0x0cc840b3, + 0x0cc881b1, 0x0cc9422f, 0x0cca4131, 0x0ccac0b5, + 0x0ccb00b1, 0x0ccb40b3, 0x0ccb80b5, 0x0ccbc0b1, + 0x0ccc012f, 0x0ccc80b5, 0x0cccc0b3, 0x0ccd00b5, + 0x0ccd40b1, 0x0ccd80b5, 0x0ccdc085, 0x0cce02b1, + 0x0ccf40b3, 0x0ccf80b1, 0x0ccfc085, 0x0cd001b1, + 0x0cd0c0b3, 0x0cd101b1, 0x0cd1c0b5, 0x0cd200b3, + 0x0cd24085, 0x0cd280b5, 0x0cd2c085, 0x0cd30133, + 0x0cd381b1, 0x0cd440b3, 0x0cd48085, 0x0cd4c0b1, + 0x0cd500b3, 0x0cd54085, 0x0cd580b5, 0x0cd5c0b1, + 0x0cd60521, 0x0cd88525, 0x0cdb02a5, 0x0cdc4099, + 0x0cdc8117, 0x0cdd0099, 0x0cdd4197, 0x0cde0127, + 0x0cde8285, 0x0cdfc089, 0x0ce0043f, 0x0ce20099, + 0x0ce2409b, 0x0ce283bf, 0x0ce44219, 0x0ce54205, + 0x0ce6433f, 0x0ce7c131, 0x0ce84085, 0x0ce881b1, + 0x0ce94085, 0x0ce98107, 0x0cea0089, 0x0cea4097, + 0x0cea8219, 0x0ceb809d, 0x0cebc08d, 0x0cec083f, + 0x0cf00105, 0x0cf0809b, 0x0cf0c197, 0x0cf1809b, + 0x0cf1c099, 0x0cf20517, 0x0cf48099, 0x0cf4c117, + 0x0cf54119, 0x0cf5c097, 0x0cf6009b, 0x0cf64099, + 0x0cf68217, 0x0cf78119, 0x0cf804a1, 0x0cfa4525, + 0x0cfcc525, 0x0cff4125, 0x0cffc099, 0x29a70103, + 0x29dc0081, 0x29fc4215, 0x29fe0103, 0x2ad70203, + 0x2ada4081, 0x3e401482, 0x3e4a7f82, 0x3e6a3f82, + 0x3e8aa102, 0x3e9b0110, 0x3e9c2f82, 0x3eb3c590, + 0x3ec00197, 0x3ec0c119, 0x3ec1413f, 0x3ec4c2af, + 0x3ec74184, 0x3ec804ad, 0x3eca4081, 0x3eca8304, + 0x3ecc03a0, 0x3ece02a0, 0x3ecf8084, 0x3ed00120, + 0x3ed0c120, 0x3ed184ae, 0x3ed3c085, 0x3ed4312d, + 0x3ef4cbad, 0x3efa892f, 0x3eff022d, 0x3f002f2f, + 0x3f1782a5, 0x3f18c0b1, 0x3f1907af, 0x3f1cffaf, + 0x3f3c81a5, 0x3f3d64af, 0x3f542031, 0x3f649b31, + 0x3f7c0131, 0x3f7c83b3, 0x3f7e40b1, 0x3f7e80bd, + 0x3f7ec0bb, 0x3f7f00b3, 0x3f840503, 0x3f8c01ad, + 0x3f8cc315, 0x3f8e462d, 0x3f91cc03, 0x3f97c695, + 0x3f9c01af, 0x3f9d0085, 0x3f9d852f, 0x3fa03aad, + 0x3fbd442f, 0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad, + 0x3fe80081, 0x3fe84f1f, 0x3ff0831f, 0x3ff2831f, + 0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41724092, + 0x41790092, 0x41e04d83, 0x41e70f91, 0x44268192, + 0x442ac092, 0x444b8112, 0x44d2c112, 0x44e0c192, + 0x44e38092, 0x44e44092, 0x44f14212, 0x452ec212, + 0x456e8112, 0x464e0092, 0x58484412, 0x5b5a0192, + 0x73358d1f, 0x733c051f, 0x74578392, 0x746ec312, + 0x75000d1f, 0x75068d1f, 0x750d0d1f, 0x7513839f, + 0x7515891f, 0x751a0d1f, 0x75208d1f, 0x75271015, + 0x752f439f, 0x7531459f, 0x75340d1f, 0x753a8d1f, + 0x75410395, 0x7543441f, 0x7545839f, 0x75478d1f, + 0x754e0795, 0x7552839f, 0x75548d1f, 0x755b0d1f, + 0x75618d1f, 0x75680d1f, 0x756e8d1f, 0x75750d1f, + 0x757b8d1f, 0x75820d1f, 0x75888d1f, 0x758f0d1f, + 0x75958d1f, 0x759c0d1f, 0x75a28d1f, 0x75a90103, + 0x75aa089f, 0x75ae4081, 0x75ae839f, 0x75b04081, + 0x75b08c9f, 0x75b6c081, 0x75b7032d, 0x75b8889f, + 0x75bcc081, 0x75bd039f, 0x75bec081, 0x75bf0c9f, + 0x75c54081, 0x75c5832d, 0x75c7089f, 0x75cb4081, + 0x75cb839f, 0x75cd4081, 0x75cd8c9f, 0x75d3c081, + 0x75d4032d, 0x75d5889f, 0x75d9c081, 0x75da039f, + 0x75dbc081, 0x75dc0c9f, 0x75e24081, 0x75e2832d, + 0x75e4089f, 0x75e84081, 0x75e8839f, 0x75ea4081, + 0x75ea8c9f, 0x75f0c081, 0x75f1042d, 0x75f3851f, + 0x75f6051f, 0x75f8851f, 0x75fb051f, 0x75fd851f, + 0x780c049f, 0x780e419f, 0x780f059f, 0x7811c203, + 0x7812d0ad, 0x781b0103, 0x7b80022d, 0x7b814dad, + 0x7b884203, 0x7b89c081, 0x7b8a452d, 0x7b8d0403, + 0x7b908081, 0x7b91dc03, 0x7ba0052d, 0x7ba2c8ad, + 0x7ba84483, 0x7baac8ad, 0x7c400097, 0x7c404521, + 0x7c440d25, 0x7c4a8087, 0x7c4ac115, 0x7c4b4117, + 0x7c4c0d1f, 0x7c528217, 0x7c538099, 0x7c53c097, + 0x7c5a8197, 0x7c640097, 0x7c80012f, 0x7c808081, + 0x7c841603, 0x7c9004c1, 0x7c940103, 0x7efc051f, + 0xbe0001ac, 0xbe00d110, 0xbe0947ac, 0xbe0d3910, + 0xbe29872c, 0xbe2d022c, 0xbe2e3790, 0xbe49ff90, + 0xbe69bc10, +}; + +static const uint16_t unicode_decomp_table2[709] = { + 0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008, + 0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3, + 0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8, + 0x0108, 0x010a, 0x0073, 0x0110, 0x0112, 0x0114, 0x0120, 0x012c, + 0x0144, 0x014d, 0x0153, 0x0162, 0x0168, 0x016a, 0x0176, 0x0192, + 0x0194, 0x01a9, 0x01bb, 0x01c7, 0x01d1, 0x01d5, 0x02b9, 0x01d7, + 0x003b, 0x01d9, 0x01db, 0x00b7, 0x01e1, 0x01fc, 0x020c, 0x0218, + 0x021d, 0x0223, 0x0227, 0x03a3, 0x0233, 0x023f, 0x0242, 0x024b, + 0x024e, 0x0251, 0x025d, 0x0260, 0x0269, 0x026c, 0x026f, 0x0275, + 0x0278, 0x0281, 0x028a, 0x029c, 0x029f, 0x02a3, 0x02af, 0x02b9, + 0x02c5, 0x02c9, 0x02cd, 0x02d1, 0x02d5, 0x02e7, 0x02ed, 0x02f1, + 0x02f5, 0x02f9, 0x02fd, 0x0305, 0x0309, 0x030d, 0x0313, 0x0317, + 0x031b, 0x0323, 0x0327, 0x032b, 0x032f, 0x0335, 0x033d, 0x0341, + 0x0349, 0x034d, 0x0351, 0x0f0b, 0x0357, 0x035b, 0x035f, 0x0363, + 0x0367, 0x036b, 0x036f, 0x0373, 0x0379, 0x037d, 0x0381, 0x0385, + 0x0389, 0x038d, 0x0391, 0x0395, 0x0399, 0x039d, 0x03a1, 0x10dc, + 0x03a5, 0x03c9, 0x03cd, 0x03d9, 0x03dd, 0x03e1, 0x03ef, 0x03f1, + 0x043d, 0x044f, 0x0499, 0x04f0, 0x0502, 0x054a, 0x0564, 0x056c, + 0x0570, 0x0573, 0x059a, 0x05fa, 0x05fe, 0x0607, 0x060b, 0x0614, + 0x0618, 0x061e, 0x0622, 0x0628, 0x068e, 0x0694, 0x0698, 0x069e, + 0x06a2, 0x06ab, 0x03ac, 0x06f3, 0x03ad, 0x06f6, 0x03ae, 0x06f9, + 0x03af, 0x06fc, 0x03cc, 0x06ff, 0x03cd, 0x0702, 0x03ce, 0x0705, + 0x0709, 0x070d, 0x0711, 0x0386, 0x0732, 0x0735, 0x03b9, 0x0737, + 0x073b, 0x0388, 0x0753, 0x0389, 0x0756, 0x0390, 0x076b, 0x038a, + 0x0777, 0x03b0, 0x0789, 0x038e, 0x0799, 0x079f, 0x07a3, 0x038c, + 0x07b8, 0x038f, 0x07bb, 0x00b4, 0x07be, 0x07c0, 0x07c2, 0x2010, + 0x07cb, 0x002e, 0x07cd, 0x07cf, 0x0020, 0x07d2, 0x07d6, 0x07db, + 0x07df, 0x07e4, 0x07ea, 0x07f0, 0x0020, 0x07f6, 0x2212, 0x0801, + 0x0805, 0x0807, 0x081d, 0x0825, 0x0827, 0x0043, 0x082d, 0x0830, + 0x0190, 0x0836, 0x0839, 0x004e, 0x0845, 0x0847, 0x084c, 0x084e, + 0x0851, 0x005a, 0x03a9, 0x005a, 0x0853, 0x0857, 0x0860, 0x0069, + 0x0862, 0x0865, 0x086f, 0x0874, 0x087a, 0x087e, 0x08a2, 0x0049, + 0x08a4, 0x08a6, 0x08a9, 0x0056, 0x08ab, 0x08ad, 0x08b0, 0x08b4, + 0x0058, 0x08b6, 0x08b8, 0x08bb, 0x08c0, 0x08c2, 0x08c5, 0x0076, + 0x08c7, 0x08c9, 0x08cc, 0x08d0, 0x0078, 0x08d2, 0x08d4, 0x08d7, + 0x08db, 0x08de, 0x08e4, 0x08e7, 0x08f0, 0x08f3, 0x08f6, 0x08f9, + 0x0902, 0x0906, 0x090b, 0x090f, 0x0914, 0x0917, 0x091a, 0x0923, + 0x092c, 0x093b, 0x093e, 0x0941, 0x0944, 0x0947, 0x094a, 0x0956, + 0x095c, 0x0960, 0x0962, 0x0964, 0x0968, 0x096a, 0x0970, 0x0978, + 0x097c, 0x0980, 0x0986, 0x0989, 0x098f, 0x0991, 0x0030, 0x0993, + 0x0999, 0x099c, 0x099e, 0x09a1, 0x09a4, 0x2d61, 0x6bcd, 0x9f9f, + 0x09a6, 0x09b1, 0x09bc, 0x09c7, 0x0a95, 0x0aa1, 0x0b15, 0x0020, + 0x0b27, 0x0b31, 0x0b8d, 0x0ba1, 0x0ba5, 0x0ba9, 0x0bad, 0x0bb1, + 0x0bb5, 0x0bb9, 0x0bbd, 0x0bc1, 0x0bc5, 0x0c21, 0x0c35, 0x0c39, + 0x0c3d, 0x0c41, 0x0c45, 0x0c49, 0x0c4d, 0x0c51, 0x0c55, 0x0c59, + 0x0c6f, 0x0c71, 0x0c73, 0x0ca0, 0x0cbc, 0x0cdc, 0x0ce4, 0x0cec, + 0x0cf4, 0x0cfc, 0x0d04, 0x0d0c, 0x0d14, 0x0d22, 0x0d2e, 0x0d7a, + 0x0d82, 0x0d85, 0x0d89, 0x0d8d, 0x0d9d, 0x0db1, 0x0db5, 0x0dbc, + 0x0dc2, 0x0dc6, 0x0e28, 0x0e2c, 0x0e30, 0x0e32, 0x0e36, 0x0e3c, + 0x0e3e, 0x0e41, 0x0e43, 0x0e46, 0x0e77, 0x0e7b, 0x0e89, 0x0e8e, + 0x0e94, 0x0e9c, 0x0ea3, 0x0ea9, 0x0eb4, 0x0ebe, 0x0ec6, 0x0eca, + 0x0ecf, 0x0ed9, 0x0edd, 0x0ee4, 0x0eec, 0x0ef3, 0x0ef8, 0x0f04, + 0x0f0a, 0x0f15, 0x0f1b, 0x0f22, 0x0f28, 0x0f33, 0x0f3d, 0x0f45, + 0x0f4c, 0x0f51, 0x0f57, 0x0f5e, 0x0f63, 0x0f69, 0x0f70, 0x0f76, + 0x0f7d, 0x0f82, 0x0f89, 0x0f8d, 0x0f9e, 0x0fa4, 0x0fa9, 0x0fad, + 0x0fb8, 0x0fbe, 0x0fc9, 0x0fd0, 0x0fd6, 0x0fda, 0x0fe1, 0x0fe5, + 0x0fef, 0x0ffa, 0x1000, 0x1004, 0x1009, 0x100f, 0x1013, 0x101a, + 0x101f, 0x1023, 0x1029, 0x102f, 0x1032, 0x1036, 0x1039, 0x103f, + 0x1045, 0x1059, 0x1061, 0x1079, 0x107c, 0x1080, 0x1095, 0x10a1, + 0x10b1, 0x10c3, 0x10cb, 0x10cf, 0x10da, 0x10de, 0x10ea, 0x10f2, + 0x10f4, 0x1100, 0x1105, 0x1111, 0x1141, 0x1149, 0x114d, 0x1153, + 0x1157, 0x115a, 0x116e, 0x1171, 0x1175, 0x117b, 0x117d, 0x1181, + 0x1184, 0x118c, 0x1192, 0x1196, 0x119c, 0x11a2, 0x11a8, 0x11ab, + 0xa76f, 0x11af, 0x11b3, 0x11b7, 0x028d, 0x11bf, 0x1211, 0x130f, + 0x140d, 0x1491, 0x1496, 0x1554, 0x156d, 0x1573, 0x1579, 0x157f, + 0x158b, 0x1597, 0x002b, 0x15a2, 0x15ba, 0x15be, 0x15c2, 0x15c6, + 0x15ca, 0x15ce, 0x15e2, 0x15e6, 0x164a, 0x1663, 0x1689, 0x168f, + 0x174d, 0x1753, 0x1758, 0x1778, 0x1878, 0x187e, 0x1912, 0x19d4, + 0x1a78, 0x1a80, 0x1a9e, 0x1aa3, 0x1ab7, 0x1ac1, 0x1ac7, 0x1adb, + 0x1ae0, 0x1ae6, 0x1af4, 0x1b24, 0x1b31, 0x1b39, 0x1b3d, 0x1b53, + 0x1bca, 0x1bdc, 0x1bde, 0x1be0, 0x3164, 0x1c21, 0x1c23, 0x1c25, + 0x1c27, 0x1c29, 0x1c2b, 0x1c49, 0x1c4e, 0x1c53, 0x1c89, 0x1ccf, + 0x1cdd, 0x1ce2, 0x1ceb, 0x1cf4, 0x1d02, 0x1d07, 0x1d0c, 0x1d1e, + 0x1d30, 0x1d39, 0x1d3e, 0x1d62, 0x1d70, 0x1d72, 0x1d74, 0x1d94, + 0x1daf, 0x1db1, 0x1db3, 0x1db5, 0x1db7, 0x1db9, 0x1dbb, 0x1dbd, + 0x1ddd, 0x1ddf, 0x1de1, 0x1de3, 0x1de5, 0x1dec, 0x1dee, 0x1df0, + 0x1df2, 0x1e01, 0x1e03, 0x1e05, 0x1e07, 0x1e09, 0x1e0b, 0x1e0d, + 0x1e0f, 0x1e11, 0x1e13, 0x1e15, 0x1e17, 0x1e19, 0x1e1b, 0x1e1d, + 0x1e21, 0x03f4, 0x1e23, 0x2207, 0x1e25, 0x2202, 0x1e27, 0x1e2f, + 0x03f4, 0x1e31, 0x2207, 0x1e33, 0x2202, 0x1e35, 0x1e3d, 0x03f4, + 0x1e3f, 0x2207, 0x1e41, 0x2202, 0x1e43, 0x1e4b, 0x03f4, 0x1e4d, + 0x2207, 0x1e4f, 0x2202, 0x1e51, 0x1e59, 0x03f4, 0x1e5b, 0x2207, + 0x1e5d, 0x2202, 0x1e5f, 0x1e69, 0x1e6b, 0x1e6d, 0x1e6f, 0x1e71, + 0x1e73, 0x1e75, 0x1e77, 0x1e79, 0x1e81, 0x1ea4, 0x1ea8, 0x1eae, + 0x1ecb, 0x062d, 0x1ed3, 0x1edf, 0x062c, 0x1eef, 0x1f5f, 0x1f6b, + 0x1f7e, 0x1f90, 0x1fa3, 0x1fa5, 0x1fa9, 0x1faf, 0x1fb5, 0x1fb7, + 0x1fbb, 0x1fbd, 0x1fc5, 0x1fc8, 0x1fca, 0x1fd0, 0x1fd2, 0x30b5, + 0x1fd8, 0x2030, 0x2046, 0x204a, 0x204c, 0x2051, 0x209e, 0x20af, + 0x21b0, 0x21c0, 0x21c6, 0x22c0, 0x23de, +}; + +static const uint8_t unicode_decomp_data[9452] = { + 0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81, + 0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31, + 0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41, + 0x81, 0x41, 0x82, 0x41, 0x83, 0x41, 0x88, 0x41, + 0x8a, 0x00, 0x00, 0x43, 0xa7, 0x45, 0x80, 0x45, + 0x81, 0x45, 0x82, 0x45, 0x88, 0x49, 0x80, 0x49, + 0x81, 0x49, 0x82, 0x49, 0x88, 0x00, 0x00, 0x4e, + 0x83, 0x4f, 0x80, 0x4f, 0x81, 0x4f, 0x82, 0x4f, + 0x83, 0x4f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x55, + 0x80, 0x55, 0x81, 0x55, 0x82, 0x55, 0x88, 0x59, + 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x61, + 0x81, 0x61, 0x82, 0x61, 0x83, 0x61, 0x88, 0x61, + 0x8a, 0x00, 0x00, 0x63, 0xa7, 0x65, 0x80, 0x65, + 0x81, 0x65, 0x82, 0x65, 0x88, 0x69, 0x80, 0x69, + 0x81, 0x69, 0x82, 0x69, 0x88, 0x00, 0x00, 0x6e, + 0x83, 0x6f, 0x80, 0x6f, 0x81, 0x6f, 0x82, 0x6f, + 0x83, 0x6f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x75, + 0x80, 0x75, 0x81, 0x75, 0x82, 0x75, 0x88, 0x79, + 0x81, 0x00, 0x00, 0x79, 0x88, 0x41, 0x84, 0x41, + 0x86, 0x41, 0xa8, 0x43, 0x81, 0x43, 0x82, 0x43, + 0x87, 0x43, 0x8c, 0x44, 0x8c, 0x45, 0x84, 0x45, + 0x86, 0x45, 0x87, 0x45, 0xa8, 0x45, 0x8c, 0x47, + 0x82, 0x47, 0x86, 0x47, 0x87, 0x47, 0xa7, 0x48, + 0x82, 0x49, 0x83, 0x49, 0x84, 0x49, 0x86, 0x49, + 0xa8, 0x49, 0x87, 0x49, 0x4a, 0x69, 0x6a, 0x4a, + 0x82, 0x4b, 0xa7, 0x4c, 0x81, 0x4c, 0xa7, 0x4c, + 0x8c, 0x4c, 0x00, 0x00, 0x6b, 0x20, 0x6b, 0x4e, + 0x81, 0x4e, 0xa7, 0x4e, 0x8c, 0xbc, 0x02, 0x6e, + 0x4f, 0x84, 0x4f, 0x86, 0x4f, 0x8b, 0x52, 0x81, + 0x52, 0xa7, 0x52, 0x8c, 0x53, 0x81, 0x53, 0x82, + 0x53, 0xa7, 0x53, 0x8c, 0x54, 0xa7, 0x54, 0x8c, + 0x55, 0x83, 0x55, 0x84, 0x55, 0x86, 0x55, 0x8a, + 0x55, 0x8b, 0x55, 0xa8, 0x57, 0x82, 0x59, 0x82, + 0x59, 0x88, 0x5a, 0x81, 0x5a, 0x87, 0x5a, 0x8c, + 0x4f, 0x9b, 0x55, 0x9b, 0x44, 0x00, 0x7d, 0x01, + 0x44, 0x00, 0x7e, 0x01, 0x64, 0x00, 0x7e, 0x01, + 0x4c, 0x4a, 0x4c, 0x6a, 0x6c, 0x6a, 0x4e, 0x4a, + 0x4e, 0x6a, 0x6e, 0x6a, 0x41, 0x00, 0x8c, 0x49, + 0x00, 0x8c, 0x4f, 0x00, 0x8c, 0x55, 0x00, 0x8c, + 0xdc, 0x00, 0x84, 0xdc, 0x00, 0x81, 0xdc, 0x00, + 0x8c, 0xdc, 0x00, 0x80, 0xc4, 0x00, 0x84, 0x26, + 0x02, 0x84, 0xc6, 0x00, 0x84, 0x47, 0x8c, 0x4b, + 0x8c, 0x4f, 0xa8, 0xea, 0x01, 0x84, 0xeb, 0x01, + 0x84, 0xb7, 0x01, 0x8c, 0x92, 0x02, 0x8c, 0x6a, + 0x00, 0x8c, 0x44, 0x5a, 0x44, 0x7a, 0x64, 0x7a, + 0x47, 0x81, 0x4e, 0x00, 0x80, 0xc5, 0x00, 0x81, + 0xc6, 0x00, 0x81, 0xd8, 0x00, 0x81, 0x41, 0x8f, + 0x41, 0x91, 0x45, 0x8f, 0x45, 0x91, 0x49, 0x8f, + 0x49, 0x91, 0x4f, 0x8f, 0x4f, 0x91, 0x52, 0x8f, + 0x52, 0x91, 0x55, 0x8f, 0x55, 0x91, 0x53, 0xa6, + 0x54, 0xa6, 0x48, 0x8c, 0x41, 0x00, 0x87, 0x45, + 0x00, 0xa7, 0xd6, 0x00, 0x84, 0xd5, 0x00, 0x84, + 0x4f, 0x00, 0x87, 0x2e, 0x02, 0x84, 0x59, 0x00, + 0x84, 0x68, 0x00, 0x66, 0x02, 0x6a, 0x00, 0x72, + 0x00, 0x79, 0x02, 0x7b, 0x02, 0x81, 0x02, 0x77, + 0x00, 0x79, 0x00, 0x20, 0x86, 0x20, 0x87, 0x20, + 0x8a, 0x20, 0xa8, 0x20, 0x83, 0x20, 0x8b, 0x63, + 0x02, 0x6c, 0x00, 0x73, 0x00, 0x78, 0x00, 0x95, + 0x02, 0x80, 0x81, 0x00, 0x93, 0x88, 0x81, 0x20, + 0xc5, 0x20, 0x81, 0xa8, 0x00, 0x81, 0x91, 0x03, + 0x81, 0x95, 0x03, 0x81, 0x97, 0x03, 0x81, 0x99, + 0x03, 0x81, 0x00, 0x00, 0x00, 0x9f, 0x03, 0x81, + 0x00, 0x00, 0x00, 0xa5, 0x03, 0x81, 0xa9, 0x03, + 0x81, 0xca, 0x03, 0x81, 0x01, 0x03, 0x98, 0x07, + 0xa4, 0x07, 0xb0, 0x00, 0xb4, 0x00, 0xb6, 0x00, + 0xb8, 0x00, 0xca, 0x00, 0x01, 0x03, 0xb8, 0x07, + 0xc4, 0x07, 0xbe, 0x00, 0xc4, 0x00, 0xc8, 0x00, + 0xa5, 0x03, 0x0d, 0x13, 0x00, 0x01, 0x03, 0xd1, + 0x00, 0xd1, 0x07, 0xc6, 0x03, 0xc0, 0x03, 0xba, + 0x03, 0xc1, 0x03, 0xc2, 0x03, 0x00, 0x00, 0x98, + 0x03, 0xb5, 0x03, 0x15, 0x04, 0x80, 0x15, 0x04, + 0x88, 0x00, 0x00, 0x00, 0x13, 0x04, 0x81, 0x06, + 0x04, 0x88, 0x1a, 0x04, 0x81, 0x18, 0x04, 0x80, + 0x23, 0x04, 0x86, 0x18, 0x04, 0x86, 0x38, 0x04, + 0x86, 0x35, 0x04, 0x80, 0x35, 0x04, 0x88, 0x00, + 0x00, 0x00, 0x33, 0x04, 0x81, 0x56, 0x04, 0x88, + 0x3a, 0x04, 0x81, 0x38, 0x04, 0x80, 0x43, 0x04, + 0x86, 0x74, 0x04, 0x8f, 0x16, 0x04, 0x86, 0x10, + 0x04, 0x86, 0x10, 0x04, 0x88, 0x15, 0x04, 0x86, + 0xd8, 0x04, 0x88, 0x16, 0x04, 0x88, 0x17, 0x04, + 0x88, 0x18, 0x04, 0x84, 0x18, 0x04, 0x88, 0x1e, + 0x04, 0x88, 0xe8, 0x04, 0x88, 0x2d, 0x04, 0x88, + 0x23, 0x04, 0x84, 0x23, 0x04, 0x88, 0x23, 0x04, + 0x8b, 0x27, 0x04, 0x88, 0x2b, 0x04, 0x88, 0x65, + 0x05, 0x82, 0x05, 0x27, 0x06, 0x00, 0x2c, 0x00, + 0x2d, 0x21, 0x2d, 0x00, 0x2e, 0x23, 0x2d, 0x27, + 0x06, 0x00, 0x4d, 0x21, 0x4d, 0xa0, 0x4d, 0x23, + 0x4d, 0xd5, 0x06, 0x54, 0x06, 0x00, 0x00, 0x00, + 0x00, 0xc1, 0x06, 0x54, 0x06, 0xd2, 0x06, 0x54, + 0x06, 0x28, 0x09, 0x3c, 0x09, 0x30, 0x09, 0x3c, + 0x09, 0x33, 0x09, 0x3c, 0x09, 0x15, 0x09, 0x00, + 0x27, 0x01, 0x27, 0x02, 0x27, 0x07, 0x27, 0x0c, + 0x27, 0x0d, 0x27, 0x16, 0x27, 0x1a, 0x27, 0xbe, + 0x09, 0x09, 0x00, 0x09, 0x19, 0xa1, 0x09, 0xbc, + 0x09, 0xaf, 0x09, 0xbc, 0x09, 0x32, 0x0a, 0x3c, + 0x0a, 0x38, 0x0a, 0x3c, 0x0a, 0x16, 0x0a, 0x00, + 0x26, 0x01, 0x26, 0x06, 0x26, 0x2b, 0x0a, 0x3c, + 0x0a, 0x47, 0x0b, 0x56, 0x0b, 0x3e, 0x0b, 0x09, + 0x00, 0x09, 0x19, 0x21, 0x0b, 0x3c, 0x0b, 0x92, + 0x0b, 0xd7, 0x0b, 0xbe, 0x0b, 0x08, 0x00, 0x09, + 0x00, 0x08, 0x19, 0x46, 0x0c, 0x56, 0x0c, 0xbf, + 0x0c, 0xd5, 0x0c, 0xc6, 0x0c, 0xd5, 0x0c, 0xc2, + 0x0c, 0x04, 0x00, 0x08, 0x13, 0x3e, 0x0d, 0x08, + 0x00, 0x09, 0x00, 0x08, 0x19, 0xd9, 0x0d, 0xca, + 0x0d, 0xca, 0x0d, 0x0f, 0x05, 0x12, 0x00, 0x0f, + 0x15, 0x4d, 0x0e, 0x32, 0x0e, 0xcd, 0x0e, 0xb2, + 0x0e, 0x99, 0x0e, 0x12, 0x00, 0x12, 0x08, 0x42, + 0x0f, 0xb7, 0x0f, 0x4c, 0x0f, 0xb7, 0x0f, 0x51, + 0x0f, 0xb7, 0x0f, 0x56, 0x0f, 0xb7, 0x0f, 0x5b, + 0x0f, 0xb7, 0x0f, 0x40, 0x0f, 0xb5, 0x0f, 0x71, + 0x0f, 0x72, 0x0f, 0x71, 0x0f, 0x00, 0x03, 0x41, + 0x0f, 0xb2, 0x0f, 0x81, 0x0f, 0xb3, 0x0f, 0x80, + 0x0f, 0xb3, 0x0f, 0x81, 0x0f, 0x71, 0x0f, 0x80, + 0x0f, 0x92, 0x0f, 0xb7, 0x0f, 0x9c, 0x0f, 0xb7, + 0x0f, 0xa1, 0x0f, 0xb7, 0x0f, 0xa6, 0x0f, 0xb7, + 0x0f, 0xab, 0x0f, 0xb7, 0x0f, 0x90, 0x0f, 0xb5, + 0x0f, 0x25, 0x10, 0x2e, 0x10, 0x05, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x09, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x1b, 0x35, + 0x1b, 0x11, 0x1b, 0x35, 0x1b, 0x3a, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1b, 0x35, + 0x1b, 0x3e, 0x1b, 0x35, 0x1b, 0x42, 0x1b, 0x35, + 0x1b, 0x41, 0x00, 0xc6, 0x00, 0x42, 0x00, 0x00, + 0x00, 0x44, 0x00, 0x45, 0x00, 0x8e, 0x01, 0x47, + 0x00, 0x4f, 0x00, 0x22, 0x02, 0x50, 0x00, 0x52, + 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x61, + 0x00, 0x50, 0x02, 0x51, 0x02, 0x02, 0x1d, 0x62, + 0x00, 0x64, 0x00, 0x65, 0x00, 0x59, 0x02, 0x5b, + 0x02, 0x5c, 0x02, 0x67, 0x00, 0x00, 0x00, 0x6b, + 0x00, 0x6d, 0x00, 0x4b, 0x01, 0x6f, 0x00, 0x54, + 0x02, 0x16, 0x1d, 0x17, 0x1d, 0x70, 0x00, 0x74, + 0x00, 0x75, 0x00, 0x1d, 0x1d, 0x6f, 0x02, 0x76, + 0x00, 0x25, 0x1d, 0xb2, 0x03, 0xb3, 0x03, 0xb4, + 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x69, 0x00, 0x72, + 0x00, 0x75, 0x00, 0x76, 0x00, 0xb2, 0x03, 0xb3, + 0x03, 0xc1, 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x52, + 0x02, 0x63, 0x00, 0x55, 0x02, 0xf0, 0x00, 0x5c, + 0x02, 0x66, 0x00, 0x5f, 0x02, 0x61, 0x02, 0x65, + 0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x7b, + 0x1d, 0x9d, 0x02, 0x6d, 0x02, 0x85, 0x1d, 0x9f, + 0x02, 0x71, 0x02, 0x70, 0x02, 0x72, 0x02, 0x73, + 0x02, 0x74, 0x02, 0x75, 0x02, 0x78, 0x02, 0x82, + 0x02, 0x83, 0x02, 0xab, 0x01, 0x89, 0x02, 0x8a, + 0x02, 0x1c, 0x1d, 0x8b, 0x02, 0x8c, 0x02, 0x7a, + 0x00, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0xb8, + 0x03, 0x41, 0x00, 0xa5, 0x42, 0x00, 0x87, 0x42, + 0x00, 0xa3, 0x42, 0x00, 0xb1, 0xc7, 0x00, 0x81, + 0x44, 0x00, 0x87, 0x44, 0x00, 0xa3, 0x44, 0x00, + 0xb1, 0x44, 0x00, 0xa7, 0x44, 0x00, 0xad, 0x12, + 0x01, 0x80, 0x12, 0x01, 0x81, 0x45, 0x00, 0xad, + 0x45, 0x00, 0xb0, 0x28, 0x02, 0x86, 0x46, 0x00, + 0x87, 0x47, 0x00, 0x84, 0x48, 0x00, 0x87, 0x48, + 0x00, 0xa3, 0x48, 0x00, 0x88, 0x48, 0x00, 0xa7, + 0x48, 0x00, 0xae, 0x49, 0x00, 0xb0, 0xcf, 0x00, + 0x81, 0x4b, 0x00, 0x81, 0x4b, 0x00, 0xa3, 0x4b, + 0x00, 0xb1, 0x4c, 0x00, 0xa3, 0x36, 0x1e, 0x84, + 0x4c, 0xb1, 0x4c, 0xad, 0x4d, 0x81, 0x4d, 0x87, + 0x4d, 0xa3, 0x4e, 0x87, 0x4e, 0xa3, 0x4e, 0xb1, + 0x4e, 0xad, 0xd5, 0x00, 0x81, 0xd5, 0x00, 0x88, + 0x4c, 0x01, 0x80, 0x4c, 0x01, 0x81, 0x50, 0x00, + 0x81, 0x50, 0x00, 0x87, 0x52, 0x00, 0x87, 0x52, + 0x00, 0xa3, 0x5a, 0x1e, 0x84, 0x52, 0x00, 0xb1, + 0x53, 0x00, 0x87, 0x53, 0x00, 0xa3, 0x5a, 0x01, + 0x87, 0x60, 0x01, 0x87, 0x62, 0x1e, 0x87, 0x54, + 0x00, 0x87, 0x54, 0x00, 0xa3, 0x54, 0x00, 0xb1, + 0x54, 0x00, 0xad, 0x55, 0x00, 0xa4, 0x55, 0x00, + 0xb0, 0x55, 0x00, 0xad, 0x68, 0x01, 0x81, 0x6a, + 0x01, 0x88, 0x56, 0x83, 0x56, 0xa3, 0x57, 0x80, + 0x57, 0x81, 0x57, 0x88, 0x57, 0x87, 0x57, 0xa3, + 0x58, 0x87, 0x58, 0x88, 0x59, 0x87, 0x5a, 0x82, + 0x5a, 0xa3, 0x5a, 0xb1, 0x68, 0xb1, 0x74, 0x88, + 0x77, 0x8a, 0x79, 0x8a, 0x61, 0x00, 0xbe, 0x02, + 0x7f, 0x01, 0x87, 0x41, 0x00, 0xa3, 0x41, 0x00, + 0x89, 0xc2, 0x00, 0x81, 0xc2, 0x00, 0x80, 0xc2, + 0x00, 0x89, 0xc2, 0x00, 0x83, 0xa0, 0x1e, 0x82, + 0x02, 0x01, 0x81, 0x02, 0x01, 0x80, 0x02, 0x01, + 0x89, 0x02, 0x01, 0x83, 0xa0, 0x1e, 0x86, 0x45, + 0x00, 0xa3, 0x45, 0x00, 0x89, 0x45, 0x00, 0x83, + 0xca, 0x00, 0x81, 0xca, 0x00, 0x80, 0xca, 0x00, + 0x89, 0xca, 0x00, 0x83, 0xb8, 0x1e, 0x82, 0x49, + 0x00, 0x89, 0x49, 0x00, 0xa3, 0x4f, 0x00, 0xa3, + 0x4f, 0x00, 0x89, 0xd4, 0x00, 0x81, 0xd4, 0x00, + 0x80, 0xd4, 0x00, 0x89, 0xd4, 0x00, 0x83, 0xcc, + 0x1e, 0x82, 0xa0, 0x01, 0x81, 0xa0, 0x01, 0x80, + 0xa0, 0x01, 0x89, 0xa0, 0x01, 0x83, 0xa0, 0x01, + 0xa3, 0x55, 0x00, 0xa3, 0x55, 0x00, 0x89, 0xaf, + 0x01, 0x81, 0xaf, 0x01, 0x80, 0xaf, 0x01, 0x89, + 0xaf, 0x01, 0x83, 0xaf, 0x01, 0xa3, 0x59, 0x00, + 0x80, 0x59, 0x00, 0xa3, 0x59, 0x00, 0x89, 0x59, + 0x00, 0x83, 0xb1, 0x03, 0x13, 0x03, 0x00, 0x1f, + 0x80, 0x00, 0x1f, 0x81, 0x00, 0x1f, 0xc2, 0x91, + 0x03, 0x13, 0x03, 0x08, 0x1f, 0x80, 0x08, 0x1f, + 0x81, 0x08, 0x1f, 0xc2, 0xb5, 0x03, 0x13, 0x03, + 0x10, 0x1f, 0x80, 0x10, 0x1f, 0x81, 0x95, 0x03, + 0x13, 0x03, 0x18, 0x1f, 0x80, 0x18, 0x1f, 0x81, + 0xb7, 0x03, 0x93, 0xb7, 0x03, 0x94, 0x20, 0x1f, + 0x80, 0x21, 0x1f, 0x80, 0x20, 0x1f, 0x81, 0x21, + 0x1f, 0x81, 0x20, 0x1f, 0xc2, 0x21, 0x1f, 0xc2, + 0x97, 0x03, 0x93, 0x97, 0x03, 0x94, 0x28, 0x1f, + 0x80, 0x29, 0x1f, 0x80, 0x28, 0x1f, 0x81, 0x29, + 0x1f, 0x81, 0x28, 0x1f, 0xc2, 0x29, 0x1f, 0xc2, + 0xb9, 0x03, 0x93, 0xb9, 0x03, 0x94, 0x30, 0x1f, + 0x80, 0x31, 0x1f, 0x80, 0x30, 0x1f, 0x81, 0x31, + 0x1f, 0x81, 0x30, 0x1f, 0xc2, 0x31, 0x1f, 0xc2, + 0x99, 0x03, 0x93, 0x99, 0x03, 0x94, 0x38, 0x1f, + 0x80, 0x39, 0x1f, 0x80, 0x38, 0x1f, 0x81, 0x39, + 0x1f, 0x81, 0x38, 0x1f, 0xc2, 0x39, 0x1f, 0xc2, + 0xbf, 0x03, 0x93, 0xbf, 0x03, 0x94, 0x40, 0x1f, + 0x80, 0x40, 0x1f, 0x81, 0x9f, 0x03, 0x13, 0x03, + 0x48, 0x1f, 0x80, 0x48, 0x1f, 0x81, 0xc5, 0x03, + 0x13, 0x03, 0x50, 0x1f, 0x80, 0x50, 0x1f, 0x81, + 0x50, 0x1f, 0xc2, 0xa5, 0x03, 0x94, 0x00, 0x00, + 0x00, 0x59, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x59, + 0x1f, 0x81, 0x00, 0x00, 0x00, 0x59, 0x1f, 0xc2, + 0xc9, 0x03, 0x93, 0xc9, 0x03, 0x94, 0x60, 0x1f, + 0x80, 0x61, 0x1f, 0x80, 0x60, 0x1f, 0x81, 0x61, + 0x1f, 0x81, 0x60, 0x1f, 0xc2, 0x61, 0x1f, 0xc2, + 0xa9, 0x03, 0x93, 0xa9, 0x03, 0x94, 0x68, 0x1f, + 0x80, 0x69, 0x1f, 0x80, 0x68, 0x1f, 0x81, 0x69, + 0x1f, 0x81, 0x68, 0x1f, 0xc2, 0x69, 0x1f, 0xc2, + 0xb1, 0x03, 0x80, 0xb5, 0x03, 0x80, 0xb7, 0x03, + 0x80, 0xb9, 0x03, 0x80, 0xbf, 0x03, 0x80, 0xc5, + 0x03, 0x80, 0xc9, 0x03, 0x80, 0x00, 0x1f, 0x45, + 0x03, 0x20, 0x1f, 0x45, 0x03, 0x60, 0x1f, 0x45, + 0x03, 0xb1, 0x03, 0x86, 0xb1, 0x03, 0x84, 0x70, + 0x1f, 0xc5, 0xb1, 0x03, 0xc5, 0xac, 0x03, 0xc5, + 0x00, 0x00, 0x00, 0xb1, 0x03, 0xc2, 0xb6, 0x1f, + 0xc5, 0x91, 0x03, 0x86, 0x91, 0x03, 0x84, 0x91, + 0x03, 0x80, 0x91, 0x03, 0xc5, 0x20, 0x93, 0x20, + 0x93, 0x20, 0xc2, 0xa8, 0x00, 0xc2, 0x74, 0x1f, + 0xc5, 0xb7, 0x03, 0xc5, 0xae, 0x03, 0xc5, 0x00, + 0x00, 0x00, 0xb7, 0x03, 0xc2, 0xc6, 0x1f, 0xc5, + 0x95, 0x03, 0x80, 0x97, 0x03, 0x80, 0x97, 0x03, + 0xc5, 0xbf, 0x1f, 0x80, 0xbf, 0x1f, 0x81, 0xbf, + 0x1f, 0xc2, 0xb9, 0x03, 0x86, 0xb9, 0x03, 0x84, + 0xca, 0x03, 0x80, 0x00, 0x03, 0xb9, 0x42, 0xca, + 0x42, 0x99, 0x06, 0x99, 0x04, 0x99, 0x00, 0xfe, + 0x1f, 0x80, 0xfe, 0x1f, 0x81, 0xfe, 0x1f, 0xc2, + 0xc5, 0x03, 0x86, 0xc5, 0x03, 0x84, 0xcb, 0x03, + 0x80, 0x00, 0x03, 0xc1, 0x13, 0xc1, 0x14, 0xc5, + 0x42, 0xcb, 0x42, 0xa5, 0x06, 0xa5, 0x04, 0xa5, + 0x00, 0xa1, 0x03, 0x94, 0xa8, 0x00, 0x80, 0x85, + 0x03, 0x60, 0x00, 0x7c, 0x1f, 0xc5, 0xc9, 0x03, + 0xc5, 0xce, 0x03, 0xc5, 0x00, 0x00, 0x00, 0xc9, + 0x03, 0xc2, 0xf6, 0x1f, 0xc5, 0x9f, 0x03, 0x80, + 0xa9, 0x03, 0x80, 0xa9, 0x03, 0xc5, 0x20, 0x94, + 0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0xb3, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x32, 0x20, 0x32, 0x20, 0x32, 0x20, + 0x00, 0x00, 0x00, 0x35, 0x20, 0x35, 0x20, 0x35, + 0x20, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00, + 0x20, 0x85, 0x3f, 0x3f, 0x3f, 0x21, 0x21, 0x3f, + 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x69, + 0x00, 0x00, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x2b, 0x3d, 0x28, 0x29, 0x6e, 0x30, 0x00, 0x2b, + 0x00, 0x12, 0x22, 0x3d, 0x00, 0x28, 0x00, 0x29, + 0x00, 0x00, 0x00, 0x61, 0x00, 0x65, 0x00, 0x6f, + 0x00, 0x78, 0x00, 0x59, 0x02, 0x68, 0x6b, 0x6c, + 0x6d, 0x6e, 0x70, 0x73, 0x74, 0x52, 0x73, 0x61, + 0x2f, 0x63, 0x61, 0x2f, 0x73, 0xb0, 0x00, 0x43, + 0x63, 0x2f, 0x6f, 0x63, 0x2f, 0x75, 0xb0, 0x00, + 0x46, 0x48, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, + 0xdf, 0x01, 0x01, 0x04, 0x24, 0x4e, 0x6f, 0x50, + 0x51, 0x52, 0x52, 0x52, 0x53, 0x4d, 0x54, 0x45, + 0x4c, 0x54, 0x4d, 0x4b, 0x00, 0xc5, 0x00, 0x42, + 0x43, 0x00, 0x65, 0x45, 0x46, 0x00, 0x4d, 0x6f, + 0xd0, 0x05, 0x46, 0x41, 0x58, 0xc0, 0x03, 0xb3, + 0x03, 0x93, 0x03, 0xa0, 0x03, 0x11, 0x22, 0x44, + 0x64, 0x65, 0x69, 0x6a, 0x31, 0xd0, 0x37, 0x31, + 0xd0, 0x39, 0x31, 0xd0, 0x31, 0x30, 0x31, 0xd0, + 0x33, 0x32, 0xd0, 0x33, 0x31, 0xd0, 0x35, 0x32, + 0xd0, 0x35, 0x33, 0xd0, 0x35, 0x34, 0xd0, 0x35, + 0x31, 0xd0, 0x36, 0x35, 0xd0, 0x36, 0x31, 0xd0, + 0x38, 0x33, 0xd0, 0x38, 0x35, 0xd0, 0x38, 0x37, + 0xd0, 0x38, 0x31, 0xd0, 0x49, 0x49, 0x49, 0x49, + 0x49, 0x49, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49, + 0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x49, + 0x58, 0x49, 0x49, 0x4c, 0x43, 0x44, 0x4d, 0x69, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76, 0x76, + 0x69, 0x76, 0x69, 0x69, 0x76, 0x69, 0x69, 0x69, + 0x69, 0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6c, + 0x63, 0x64, 0x6d, 0x30, 0xd0, 0x33, 0x90, 0x21, + 0xb8, 0x92, 0x21, 0xb8, 0x94, 0x21, 0xb8, 0xd0, + 0x21, 0xb8, 0xd4, 0x21, 0xb8, 0xd2, 0x21, 0xb8, + 0x03, 0x22, 0xb8, 0x08, 0x22, 0xb8, 0x0b, 0x22, + 0xb8, 0x23, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x25, + 0x22, 0xb8, 0x2b, 0x22, 0x2b, 0x22, 0x2b, 0x22, + 0x00, 0x00, 0x00, 0x2e, 0x22, 0x2e, 0x22, 0x2e, + 0x22, 0x00, 0x00, 0x00, 0x3c, 0x22, 0xb8, 0x43, + 0x22, 0xb8, 0x45, 0x22, 0xb8, 0x00, 0x00, 0x00, + 0x48, 0x22, 0xb8, 0x3d, 0x00, 0xb8, 0x00, 0x00, + 0x00, 0x61, 0x22, 0xb8, 0x4d, 0x22, 0xb8, 0x3c, + 0x00, 0xb8, 0x3e, 0x00, 0xb8, 0x64, 0x22, 0xb8, + 0x65, 0x22, 0xb8, 0x72, 0x22, 0xb8, 0x76, 0x22, + 0xb8, 0x7a, 0x22, 0xb8, 0x82, 0x22, 0xb8, 0x86, + 0x22, 0xb8, 0xa2, 0x22, 0xb8, 0xa8, 0x22, 0xb8, + 0xa9, 0x22, 0xb8, 0xab, 0x22, 0xb8, 0x7c, 0x22, + 0xb8, 0x91, 0x22, 0xb8, 0xb2, 0x22, 0x38, 0x03, + 0x08, 0x30, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00, + 0x32, 0x30, 0x28, 0x00, 0x31, 0x00, 0x29, 0x00, + 0x28, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29, 0x00, + 0x28, 0x32, 0x30, 0x29, 0x31, 0x00, 0x2e, 0x00, + 0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x30, + 0x2e, 0x28, 0x00, 0x61, 0x00, 0x29, 0x00, 0x41, + 0x00, 0x61, 0x00, 0x2b, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0xdd, 0x2a, 0xb8, 0x6a, 0x56, 0x00, 0x4e, + 0x00, 0x28, 0x36, 0x3f, 0x59, 0x85, 0x8c, 0xa0, + 0xba, 0x3f, 0x51, 0x00, 0x26, 0x2c, 0x43, 0x57, + 0x6c, 0xa1, 0xb6, 0xc1, 0x9b, 0x52, 0x00, 0x5e, + 0x7a, 0x7f, 0x9d, 0xa6, 0xc1, 0xce, 0xe7, 0xb6, + 0x53, 0xc8, 0x53, 0xe3, 0x53, 0xd7, 0x56, 0x1f, + 0x57, 0xeb, 0x58, 0x02, 0x59, 0x0a, 0x59, 0x15, + 0x59, 0x27, 0x59, 0x73, 0x59, 0x50, 0x5b, 0x80, + 0x5b, 0xf8, 0x5b, 0x0f, 0x5c, 0x22, 0x5c, 0x38, + 0x5c, 0x6e, 0x5c, 0x71, 0x5c, 0xdb, 0x5d, 0xe5, + 0x5d, 0xf1, 0x5d, 0xfe, 0x5d, 0x72, 0x5e, 0x7a, + 0x5e, 0x7f, 0x5e, 0xf4, 0x5e, 0xfe, 0x5e, 0x0b, + 0x5f, 0x13, 0x5f, 0x50, 0x5f, 0x61, 0x5f, 0x73, + 0x5f, 0xc3, 0x5f, 0x08, 0x62, 0x36, 0x62, 0x4b, + 0x62, 0x2f, 0x65, 0x34, 0x65, 0x87, 0x65, 0x97, + 0x65, 0xa4, 0x65, 0xb9, 0x65, 0xe0, 0x65, 0xe5, + 0x65, 0xf0, 0x66, 0x08, 0x67, 0x28, 0x67, 0x20, + 0x6b, 0x62, 0x6b, 0x79, 0x6b, 0xb3, 0x6b, 0xcb, + 0x6b, 0xd4, 0x6b, 0xdb, 0x6b, 0x0f, 0x6c, 0x14, + 0x6c, 0x34, 0x6c, 0x6b, 0x70, 0x2a, 0x72, 0x36, + 0x72, 0x3b, 0x72, 0x3f, 0x72, 0x47, 0x72, 0x59, + 0x72, 0x5b, 0x72, 0xac, 0x72, 0x84, 0x73, 0x89, + 0x73, 0xdc, 0x74, 0xe6, 0x74, 0x18, 0x75, 0x1f, + 0x75, 0x28, 0x75, 0x30, 0x75, 0x8b, 0x75, 0x92, + 0x75, 0x76, 0x76, 0x7d, 0x76, 0xae, 0x76, 0xbf, + 0x76, 0xee, 0x76, 0xdb, 0x77, 0xe2, 0x77, 0xf3, + 0x77, 0x3a, 0x79, 0xb8, 0x79, 0xbe, 0x79, 0x74, + 0x7a, 0xcb, 0x7a, 0xf9, 0x7a, 0x73, 0x7c, 0xf8, + 0x7c, 0x36, 0x7f, 0x51, 0x7f, 0x8a, 0x7f, 0xbd, + 0x7f, 0x01, 0x80, 0x0c, 0x80, 0x12, 0x80, 0x33, + 0x80, 0x7f, 0x80, 0x89, 0x80, 0xe3, 0x81, 0x00, + 0x07, 0x10, 0x19, 0x29, 0x38, 0x3c, 0x8b, 0x8f, + 0x95, 0x4d, 0x86, 0x6b, 0x86, 0x40, 0x88, 0x4c, + 0x88, 0x63, 0x88, 0x7e, 0x89, 0x8b, 0x89, 0xd2, + 0x89, 0x00, 0x8a, 0x37, 0x8c, 0x46, 0x8c, 0x55, + 0x8c, 0x78, 0x8c, 0x9d, 0x8c, 0x64, 0x8d, 0x70, + 0x8d, 0xb3, 0x8d, 0xab, 0x8e, 0xca, 0x8e, 0x9b, + 0x8f, 0xb0, 0x8f, 0xb5, 0x8f, 0x91, 0x90, 0x49, + 0x91, 0xc6, 0x91, 0xcc, 0x91, 0xd1, 0x91, 0x77, + 0x95, 0x80, 0x95, 0x1c, 0x96, 0xb6, 0x96, 0xb9, + 0x96, 0xe8, 0x96, 0x51, 0x97, 0x5e, 0x97, 0x62, + 0x97, 0x69, 0x97, 0xcb, 0x97, 0xed, 0x97, 0xf3, + 0x97, 0x01, 0x98, 0xa8, 0x98, 0xdb, 0x98, 0xdf, + 0x98, 0x96, 0x99, 0x99, 0x99, 0xac, 0x99, 0xa8, + 0x9a, 0xd8, 0x9a, 0xdf, 0x9a, 0x25, 0x9b, 0x2f, + 0x9b, 0x32, 0x9b, 0x3c, 0x9b, 0x5a, 0x9b, 0xe5, + 0x9c, 0x75, 0x9e, 0x7f, 0x9e, 0xa5, 0x9e, 0x00, + 0x16, 0x1e, 0x28, 0x2c, 0x54, 0x58, 0x69, 0x6e, + 0x7b, 0x96, 0xa5, 0xad, 0xe8, 0xf7, 0xfb, 0x12, + 0x30, 0x00, 0x00, 0x41, 0x53, 0x44, 0x53, 0x45, + 0x53, 0x4b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x4d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x4f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x51, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x53, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x55, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x57, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x59, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x5b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x5d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x5f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x61, 0x30, 0x99, 0x30, 0x64, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x68, 0x30, 0x99, + 0x30, 0x6f, 0x30, 0x99, 0x30, 0x72, 0x30, 0x99, + 0x30, 0x75, 0x30, 0x99, 0x30, 0x78, 0x30, 0x99, + 0x30, 0x7b, 0x30, 0x99, 0x30, 0x46, 0x30, 0x99, + 0x30, 0x20, 0x00, 0x99, 0x30, 0x9d, 0x30, 0x99, + 0x30, 0x88, 0x30, 0x8a, 0x30, 0xab, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xad, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x30, 0x99, + 0x30, 0xc4, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0xc8, 0x30, 0x99, 0x30, 0xcf, 0x30, 0x99, + 0x30, 0xd2, 0x30, 0x99, 0x30, 0xd5, 0x30, 0x99, + 0x30, 0xd8, 0x30, 0x99, 0x30, 0xdb, 0x30, 0x99, + 0x30, 0xa6, 0x30, 0x99, 0x30, 0xef, 0x30, 0x99, + 0x30, 0xfd, 0x30, 0x99, 0x30, 0xb3, 0x30, 0xc8, + 0x30, 0x00, 0x11, 0x00, 0x01, 0xaa, 0x02, 0xac, + 0xad, 0x03, 0x04, 0x05, 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0x1a, 0x06, 0x07, 0x08, 0x21, 0x09, + 0x11, 0x61, 0x11, 0x14, 0x11, 0x4c, 0x00, 0x01, + 0xb3, 0xb4, 0xb8, 0xba, 0xbf, 0xc3, 0xc5, 0x08, + 0xc9, 0xcb, 0x09, 0x0a, 0x0c, 0x0e, 0x0f, 0x13, + 0x15, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x22, + 0x2c, 0x33, 0x38, 0xdd, 0xde, 0x43, 0x44, 0x45, + 0x70, 0x71, 0x74, 0x7d, 0x7e, 0x80, 0x8a, 0x8d, + 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, + 0x0a, 0x4e, 0x2d, 0x4e, 0x0b, 0x4e, 0x32, 0x75, + 0x59, 0x4e, 0x19, 0x4e, 0x01, 0x4e, 0x29, 0x59, + 0x30, 0x57, 0xba, 0x4e, 0x28, 0x00, 0x29, 0x00, + 0x00, 0x11, 0x02, 0x11, 0x03, 0x11, 0x05, 0x11, + 0x06, 0x11, 0x07, 0x11, 0x09, 0x11, 0x0b, 0x11, + 0x0c, 0x11, 0x0e, 0x11, 0x0f, 0x11, 0x10, 0x11, + 0x11, 0x11, 0x12, 0x11, 0x28, 0x00, 0x00, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x02, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x05, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x09, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0e, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0c, 0x11, + 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, + 0x69, 0x11, 0x0c, 0x11, 0x65, 0x11, 0xab, 0x11, + 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, 0x69, 0x11, + 0x12, 0x11, 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, + 0x29, 0x00, 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, + 0xdb, 0x56, 0x94, 0x4e, 0x6d, 0x51, 0x03, 0x4e, + 0x6b, 0x51, 0x5d, 0x4e, 0x41, 0x53, 0x08, 0x67, + 0x6b, 0x70, 0x34, 0x6c, 0x28, 0x67, 0xd1, 0x91, + 0x1f, 0x57, 0xe5, 0x65, 0x2a, 0x68, 0x09, 0x67, + 0x3e, 0x79, 0x0d, 0x54, 0x79, 0x72, 0xa1, 0x8c, + 0x5d, 0x79, 0xb4, 0x52, 0xe3, 0x4e, 0x7c, 0x54, + 0x66, 0x5b, 0xe3, 0x76, 0x01, 0x4f, 0xc7, 0x8c, + 0x54, 0x53, 0x6d, 0x79, 0x11, 0x4f, 0xea, 0x81, + 0xf3, 0x81, 0x4f, 0x55, 0x7c, 0x5e, 0x87, 0x65, + 0x8f, 0x7b, 0x50, 0x54, 0x45, 0x32, 0x00, 0x31, + 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x11, 0x00, + 0x02, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x0c, + 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x00, 0x11, 0x00, + 0x61, 0x02, 0x61, 0x03, 0x61, 0x05, 0x61, 0x06, + 0x61, 0x07, 0x61, 0x09, 0x61, 0x0b, 0x61, 0x0c, + 0x61, 0x0e, 0x11, 0x61, 0x11, 0x00, 0x11, 0x0e, + 0x61, 0xb7, 0x00, 0x69, 0x0b, 0x11, 0x01, 0x63, + 0x00, 0x69, 0x0b, 0x11, 0x6e, 0x11, 0x00, 0x4e, + 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, 0x94, 0x4e, + 0x6d, 0x51, 0x03, 0x4e, 0x6b, 0x51, 0x5d, 0x4e, + 0x41, 0x53, 0x08, 0x67, 0x6b, 0x70, 0x34, 0x6c, + 0x28, 0x67, 0xd1, 0x91, 0x1f, 0x57, 0xe5, 0x65, + 0x2a, 0x68, 0x09, 0x67, 0x3e, 0x79, 0x0d, 0x54, + 0x79, 0x72, 0xa1, 0x8c, 0x5d, 0x79, 0xb4, 0x52, + 0xd8, 0x79, 0x37, 0x75, 0x73, 0x59, 0x69, 0x90, + 0x2a, 0x51, 0x70, 0x53, 0xe8, 0x6c, 0x05, 0x98, + 0x11, 0x4f, 0x99, 0x51, 0x63, 0x6b, 0x0a, 0x4e, + 0x2d, 0x4e, 0x0b, 0x4e, 0xe6, 0x5d, 0xf3, 0x53, + 0x3b, 0x53, 0x97, 0x5b, 0x66, 0x5b, 0xe3, 0x76, + 0x01, 0x4f, 0xc7, 0x8c, 0x54, 0x53, 0x1c, 0x59, + 0x33, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00, + 0x35, 0x30, 0x31, 0x00, 0x08, 0x67, 0x31, 0x00, + 0x30, 0x00, 0x08, 0x67, 0x48, 0x67, 0x65, 0x72, + 0x67, 0x65, 0x56, 0x4c, 0x54, 0x44, 0xa2, 0x30, + 0x00, 0x02, 0x04, 0x06, 0x08, 0x09, 0x0b, 0x0d, + 0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, + 0x1f, 0x22, 0x24, 0x26, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3d, + 0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0xe4, + 0x4e, 0x8c, 0x54, 0xa1, 0x30, 0x01, 0x30, 0x5b, + 0x27, 0x01, 0x4a, 0x34, 0x00, 0x01, 0x52, 0x39, + 0x01, 0xa2, 0x30, 0x00, 0x5a, 0x49, 0xa4, 0x30, + 0x00, 0x27, 0x4f, 0x0c, 0xa4, 0x30, 0x00, 0x4f, + 0x1d, 0x02, 0x05, 0x4f, 0xa8, 0x30, 0x00, 0x11, + 0x07, 0x54, 0x21, 0xa8, 0x30, 0x00, 0x54, 0x03, + 0x54, 0xa4, 0x30, 0x06, 0x4f, 0x15, 0x06, 0x58, + 0x3c, 0x07, 0x00, 0x46, 0xab, 0x30, 0x00, 0x3e, + 0x18, 0x1d, 0x00, 0x42, 0x3f, 0x51, 0xac, 0x30, + 0x00, 0x41, 0x47, 0x00, 0x47, 0x32, 0xae, 0x30, + 0xac, 0x30, 0xae, 0x30, 0x00, 0x1d, 0x4e, 0xad, + 0x30, 0x00, 0x38, 0x3d, 0x4f, 0x01, 0x3e, 0x13, + 0x4f, 0xad, 0x30, 0xed, 0x30, 0xad, 0x30, 0x00, + 0x40, 0x03, 0x3c, 0x33, 0xad, 0x30, 0x00, 0x40, + 0x34, 0x4f, 0x1b, 0x3e, 0xad, 0x30, 0x00, 0x40, + 0x42, 0x16, 0x1b, 0xb0, 0x30, 0x00, 0x39, 0x30, + 0xa4, 0x30, 0x0c, 0x45, 0x3c, 0x24, 0x4f, 0x0b, + 0x47, 0x18, 0x00, 0x49, 0xaf, 0x30, 0x00, 0x3e, + 0x4d, 0x1e, 0xb1, 0x30, 0x00, 0x4b, 0x08, 0x02, + 0x3a, 0x19, 0x02, 0x4b, 0x2c, 0xa4, 0x30, 0x11, + 0x00, 0x0b, 0x47, 0xb5, 0x30, 0x00, 0x3e, 0x0c, + 0x47, 0x2b, 0xb0, 0x30, 0x07, 0x3a, 0x43, 0x00, + 0xb9, 0x30, 0x02, 0x3a, 0x08, 0x02, 0x3a, 0x0f, + 0x07, 0x43, 0x00, 0xb7, 0x30, 0x10, 0x00, 0x12, + 0x34, 0x11, 0x3c, 0x13, 0x17, 0xa4, 0x30, 0x2a, + 0x1f, 0x24, 0x2b, 0x00, 0x20, 0xbb, 0x30, 0x16, + 0x41, 0x00, 0x38, 0x0d, 0xc4, 0x30, 0x0d, 0x38, + 0x00, 0xd0, 0x30, 0x00, 0x2c, 0x1c, 0x1b, 0xa2, + 0x30, 0x32, 0x00, 0x17, 0x26, 0x49, 0xaf, 0x30, + 0x25, 0x00, 0x3c, 0xb3, 0x30, 0x21, 0x00, 0x20, + 0x38, 0xa1, 0x30, 0x34, 0x00, 0x48, 0x22, 0x28, + 0xa3, 0x30, 0x32, 0x00, 0x59, 0x25, 0xa7, 0x30, + 0x2f, 0x1c, 0x10, 0x00, 0x44, 0xd5, 0x30, 0x00, + 0x14, 0x1e, 0xaf, 0x30, 0x29, 0x00, 0x10, 0x4d, + 0x3c, 0xda, 0x30, 0xbd, 0x30, 0xb8, 0x30, 0x22, + 0x13, 0x1a, 0x20, 0x33, 0x0c, 0x22, 0x3b, 0x01, + 0x22, 0x44, 0x00, 0x21, 0x44, 0x07, 0xa4, 0x30, + 0x39, 0x00, 0x4f, 0x24, 0xc8, 0x30, 0x14, 0x23, + 0x00, 0xdb, 0x30, 0xf3, 0x30, 0xc9, 0x30, 0x14, + 0x2a, 0x00, 0x12, 0x33, 0x22, 0x12, 0x33, 0x2a, + 0xa4, 0x30, 0x3a, 0x00, 0x0b, 0x49, 0xa4, 0x30, + 0x3a, 0x00, 0x47, 0x3a, 0x1f, 0x2b, 0x3a, 0x47, + 0x0b, 0xb7, 0x30, 0x27, 0x3c, 0x00, 0x30, 0x3c, + 0xaf, 0x30, 0x30, 0x00, 0x3e, 0x44, 0xdf, 0x30, + 0xea, 0x30, 0xd0, 0x30, 0x0f, 0x1a, 0x00, 0x2c, + 0x1b, 0xe1, 0x30, 0xac, 0x30, 0xac, 0x30, 0x35, + 0x00, 0x1c, 0x47, 0x35, 0x50, 0x1c, 0x3f, 0xa2, + 0x30, 0x42, 0x5a, 0x27, 0x42, 0x5a, 0x49, 0x44, + 0x00, 0x51, 0xc3, 0x30, 0x27, 0x00, 0x05, 0x28, + 0xea, 0x30, 0xe9, 0x30, 0xd4, 0x30, 0x17, 0x00, + 0x28, 0xd6, 0x30, 0x15, 0x26, 0x00, 0x15, 0xec, + 0x30, 0xe0, 0x30, 0xb2, 0x30, 0x3a, 0x41, 0x16, + 0x00, 0x41, 0xc3, 0x30, 0x2c, 0x00, 0x05, 0x30, + 0x00, 0xb9, 0x70, 0x31, 0x00, 0x30, 0x00, 0xb9, + 0x70, 0x32, 0x00, 0x30, 0x00, 0xb9, 0x70, 0x68, + 0x50, 0x61, 0x64, 0x61, 0x41, 0x55, 0x62, 0x61, + 0x72, 0x6f, 0x56, 0x70, 0x63, 0x64, 0x6d, 0x64, + 0x00, 0x6d, 0x00, 0xb2, 0x00, 0x49, 0x00, 0x55, + 0x00, 0x73, 0x5e, 0x10, 0x62, 0x2d, 0x66, 0x8c, + 0x54, 0x27, 0x59, 0x63, 0x6b, 0x0e, 0x66, 0xbb, + 0x6c, 0x2a, 0x68, 0x0f, 0x5f, 0x1a, 0x4f, 0x3e, + 0x79, 0x70, 0x00, 0x41, 0x6e, 0x00, 0x41, 0xbc, + 0x03, 0x41, 0x6d, 0x00, 0x41, 0x6b, 0x00, 0x41, + 0x4b, 0x00, 0x42, 0x4d, 0x00, 0x42, 0x47, 0x00, + 0x42, 0x63, 0x61, 0x6c, 0x6b, 0x63, 0x61, 0x6c, + 0x70, 0x00, 0x46, 0x6e, 0x00, 0x46, 0xbc, 0x03, + 0x46, 0xbc, 0x03, 0x67, 0x6d, 0x00, 0x67, 0x6b, + 0x00, 0x67, 0x48, 0x00, 0x7a, 0x6b, 0x48, 0x7a, + 0x4d, 0x48, 0x7a, 0x47, 0x48, 0x7a, 0x54, 0x48, + 0x7a, 0xbc, 0x03, 0x13, 0x21, 0x6d, 0x00, 0x13, + 0x21, 0x64, 0x00, 0x13, 0x21, 0x6b, 0x00, 0x13, + 0x21, 0x66, 0x00, 0x6d, 0x6e, 0x00, 0x6d, 0xbc, + 0x03, 0x6d, 0x6d, 0x00, 0x6d, 0x63, 0x00, 0x6d, + 0x6b, 0x00, 0x6d, 0x63, 0x00, 0x0a, 0x0a, 0x4f, + 0x00, 0x0a, 0x4f, 0x6d, 0x00, 0xb2, 0x00, 0x63, + 0x00, 0x08, 0x0a, 0x4f, 0x0a, 0x0a, 0x50, 0x00, + 0x0a, 0x50, 0x6d, 0x00, 0xb3, 0x00, 0x6b, 0x00, + 0x6d, 0x00, 0xb3, 0x00, 0x6d, 0x00, 0x15, 0x22, + 0x73, 0x00, 0x6d, 0x00, 0x15, 0x22, 0x73, 0x00, + 0xb2, 0x00, 0x50, 0x61, 0x6b, 0x50, 0x61, 0x4d, + 0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64, + 0x72, 0x61, 0x64, 0xd1, 0x73, 0x72, 0x00, 0x61, + 0x00, 0x64, 0x00, 0x15, 0x22, 0x73, 0x00, 0xb2, + 0x00, 0x70, 0x00, 0x73, 0x6e, 0x00, 0x73, 0xbc, + 0x03, 0x73, 0x6d, 0x00, 0x73, 0x70, 0x00, 0x56, + 0x6e, 0x00, 0x56, 0xbc, 0x03, 0x56, 0x6d, 0x00, + 0x56, 0x6b, 0x00, 0x56, 0x4d, 0x00, 0x56, 0x70, + 0x00, 0x57, 0x6e, 0x00, 0x57, 0xbc, 0x03, 0x57, + 0x6d, 0x00, 0x57, 0x6b, 0x00, 0x57, 0x4d, 0x00, + 0x57, 0x6b, 0x00, 0xa9, 0x03, 0x4d, 0x00, 0xa9, + 0x03, 0x61, 0x2e, 0x6d, 0x2e, 0x42, 0x71, 0x63, + 0x63, 0x63, 0x64, 0x43, 0xd1, 0x6b, 0x67, 0x43, + 0x6f, 0x2e, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61, + 0x48, 0x50, 0x69, 0x6e, 0x4b, 0x4b, 0x4b, 0x4d, + 0x6b, 0x74, 0x6c, 0x6d, 0x6c, 0x6e, 0x6c, 0x6f, + 0x67, 0x6c, 0x78, 0x6d, 0x62, 0x6d, 0x69, 0x6c, + 0x6d, 0x6f, 0x6c, 0x50, 0x48, 0x70, 0x2e, 0x6d, + 0x2e, 0x50, 0x50, 0x4d, 0x50, 0x52, 0x73, 0x72, + 0x53, 0x76, 0x57, 0x62, 0x56, 0xd1, 0x6d, 0x41, + 0xd1, 0x6d, 0x31, 0x00, 0xe5, 0x65, 0x31, 0x00, + 0x30, 0x00, 0xe5, 0x65, 0x32, 0x00, 0x30, 0x00, + 0xe5, 0x65, 0x33, 0x00, 0x30, 0x00, 0xe5, 0x65, + 0x67, 0x61, 0x6c, 0x4a, 0x04, 0x4c, 0x04, 0x53, + 0x43, 0x46, 0x51, 0x26, 0x01, 0x53, 0x01, 0x27, + 0xa7, 0x37, 0xab, 0x6b, 0x02, 0x52, 0xab, 0x48, + 0x8c, 0xf4, 0x66, 0xca, 0x8e, 0xc8, 0x8c, 0xd1, + 0x6e, 0x32, 0x4e, 0xe5, 0x53, 0x9c, 0x9f, 0x9c, + 0x9f, 0x51, 0x59, 0xd1, 0x91, 0x87, 0x55, 0x48, + 0x59, 0xf6, 0x61, 0x69, 0x76, 0x85, 0x7f, 0x3f, + 0x86, 0xba, 0x87, 0xf8, 0x88, 0x8f, 0x90, 0x02, + 0x6a, 0x1b, 0x6d, 0xd9, 0x70, 0xde, 0x73, 0x3d, + 0x84, 0x6a, 0x91, 0xf1, 0x99, 0x82, 0x4e, 0x75, + 0x53, 0x04, 0x6b, 0x1b, 0x72, 0x2d, 0x86, 0x1e, + 0x9e, 0x50, 0x5d, 0xeb, 0x6f, 0xcd, 0x85, 0x64, + 0x89, 0xc9, 0x62, 0xd8, 0x81, 0x1f, 0x88, 0xca, + 0x5e, 0x17, 0x67, 0x6a, 0x6d, 0xfc, 0x72, 0xce, + 0x90, 0x86, 0x4f, 0xb7, 0x51, 0xde, 0x52, 0xc4, + 0x64, 0xd3, 0x6a, 0x10, 0x72, 0xe7, 0x76, 0x01, + 0x80, 0x06, 0x86, 0x5c, 0x86, 0xef, 0x8d, 0x32, + 0x97, 0x6f, 0x9b, 0xfa, 0x9d, 0x8c, 0x78, 0x7f, + 0x79, 0xa0, 0x7d, 0xc9, 0x83, 0x04, 0x93, 0x7f, + 0x9e, 0xd6, 0x8a, 0xdf, 0x58, 0x04, 0x5f, 0x60, + 0x7c, 0x7e, 0x80, 0x62, 0x72, 0xca, 0x78, 0xc2, + 0x8c, 0xf7, 0x96, 0xd8, 0x58, 0x62, 0x5c, 0x13, + 0x6a, 0xda, 0x6d, 0x0f, 0x6f, 0x2f, 0x7d, 0x37, + 0x7e, 0x4b, 0x96, 0xd2, 0x52, 0x8b, 0x80, 0xdc, + 0x51, 0xcc, 0x51, 0x1c, 0x7a, 0xbe, 0x7d, 0xf1, + 0x83, 0x75, 0x96, 0x80, 0x8b, 0xcf, 0x62, 0x02, + 0x6a, 0xfe, 0x8a, 0x39, 0x4e, 0xe7, 0x5b, 0x12, + 0x60, 0x87, 0x73, 0x70, 0x75, 0x17, 0x53, 0xfb, + 0x78, 0xbf, 0x4f, 0xa9, 0x5f, 0x0d, 0x4e, 0xcc, + 0x6c, 0x78, 0x65, 0x22, 0x7d, 0xc3, 0x53, 0x5e, + 0x58, 0x01, 0x77, 0x49, 0x84, 0xaa, 0x8a, 0xba, + 0x6b, 0xb0, 0x8f, 0x88, 0x6c, 0xfe, 0x62, 0xe5, + 0x82, 0xa0, 0x63, 0x65, 0x75, 0xae, 0x4e, 0x69, + 0x51, 0xc9, 0x51, 0x81, 0x68, 0xe7, 0x7c, 0x6f, + 0x82, 0xd2, 0x8a, 0xcf, 0x91, 0xf5, 0x52, 0x42, + 0x54, 0x73, 0x59, 0xec, 0x5e, 0xc5, 0x65, 0xfe, + 0x6f, 0x2a, 0x79, 0xad, 0x95, 0x6a, 0x9a, 0x97, + 0x9e, 0xce, 0x9e, 0x9b, 0x52, 0xc6, 0x66, 0x77, + 0x6b, 0x62, 0x8f, 0x74, 0x5e, 0x90, 0x61, 0x00, + 0x62, 0x9a, 0x64, 0x23, 0x6f, 0x49, 0x71, 0x89, + 0x74, 0xca, 0x79, 0xf4, 0x7d, 0x6f, 0x80, 0x26, + 0x8f, 0xee, 0x84, 0x23, 0x90, 0x4a, 0x93, 0x17, + 0x52, 0xa3, 0x52, 0xbd, 0x54, 0xc8, 0x70, 0xc2, + 0x88, 0xaa, 0x8a, 0xc9, 0x5e, 0xf5, 0x5f, 0x7b, + 0x63, 0xae, 0x6b, 0x3e, 0x7c, 0x75, 0x73, 0xe4, + 0x4e, 0xf9, 0x56, 0xe7, 0x5b, 0xba, 0x5d, 0x1c, + 0x60, 0xb2, 0x73, 0x69, 0x74, 0x9a, 0x7f, 0x46, + 0x80, 0x34, 0x92, 0xf6, 0x96, 0x48, 0x97, 0x18, + 0x98, 0x8b, 0x4f, 0xae, 0x79, 0xb4, 0x91, 0xb8, + 0x96, 0xe1, 0x60, 0x86, 0x4e, 0xda, 0x50, 0xee, + 0x5b, 0x3f, 0x5c, 0x99, 0x65, 0x02, 0x6a, 0xce, + 0x71, 0x42, 0x76, 0xfc, 0x84, 0x7c, 0x90, 0x8d, + 0x9f, 0x88, 0x66, 0x2e, 0x96, 0x89, 0x52, 0x7b, + 0x67, 0xf3, 0x67, 0x41, 0x6d, 0x9c, 0x6e, 0x09, + 0x74, 0x59, 0x75, 0x6b, 0x78, 0x10, 0x7d, 0x5e, + 0x98, 0x6d, 0x51, 0x2e, 0x62, 0x78, 0x96, 0x2b, + 0x50, 0x19, 0x5d, 0xea, 0x6d, 0x2a, 0x8f, 0x8b, + 0x5f, 0x44, 0x61, 0x17, 0x68, 0x87, 0x73, 0x86, + 0x96, 0x29, 0x52, 0x0f, 0x54, 0x65, 0x5c, 0x13, + 0x66, 0x4e, 0x67, 0xa8, 0x68, 0xe5, 0x6c, 0x06, + 0x74, 0xe2, 0x75, 0x79, 0x7f, 0xcf, 0x88, 0xe1, + 0x88, 0xcc, 0x91, 0xe2, 0x96, 0x3f, 0x53, 0xba, + 0x6e, 0x1d, 0x54, 0xd0, 0x71, 0x98, 0x74, 0xfa, + 0x85, 0xa3, 0x96, 0x57, 0x9c, 0x9f, 0x9e, 0x97, + 0x67, 0xcb, 0x6d, 0xe8, 0x81, 0xcb, 0x7a, 0x20, + 0x7b, 0x92, 0x7c, 0xc0, 0x72, 0x99, 0x70, 0x58, + 0x8b, 0xc0, 0x4e, 0x36, 0x83, 0x3a, 0x52, 0x07, + 0x52, 0xa6, 0x5e, 0xd3, 0x62, 0xd6, 0x7c, 0x85, + 0x5b, 0x1e, 0x6d, 0xb4, 0x66, 0x3b, 0x8f, 0x4c, + 0x88, 0x4d, 0x96, 0x8b, 0x89, 0xd3, 0x5e, 0x40, + 0x51, 0xc0, 0x55, 0x00, 0x00, 0x00, 0x00, 0x5a, + 0x58, 0x00, 0x00, 0x74, 0x66, 0x00, 0x00, 0x00, + 0x00, 0xde, 0x51, 0x2a, 0x73, 0xca, 0x76, 0x3c, + 0x79, 0x5e, 0x79, 0x65, 0x79, 0x8f, 0x79, 0x56, + 0x97, 0xbe, 0x7c, 0xbd, 0x7f, 0x00, 0x00, 0x12, + 0x86, 0x00, 0x00, 0xf8, 0x8a, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x90, 0xfd, 0x90, 0xef, 0x98, 0xfc, + 0x98, 0x28, 0x99, 0xb4, 0x9d, 0xde, 0x90, 0xb7, + 0x96, 0xae, 0x4f, 0xe7, 0x50, 0x4d, 0x51, 0xc9, + 0x52, 0xe4, 0x52, 0x51, 0x53, 0x9d, 0x55, 0x06, + 0x56, 0x68, 0x56, 0x40, 0x58, 0xa8, 0x58, 0x64, + 0x5c, 0x6e, 0x5c, 0x94, 0x60, 0x68, 0x61, 0x8e, + 0x61, 0xf2, 0x61, 0x4f, 0x65, 0xe2, 0x65, 0x91, + 0x66, 0x85, 0x68, 0x77, 0x6d, 0x1a, 0x6e, 0x22, + 0x6f, 0x6e, 0x71, 0x2b, 0x72, 0x22, 0x74, 0x91, + 0x78, 0x3e, 0x79, 0x49, 0x79, 0x48, 0x79, 0x50, + 0x79, 0x56, 0x79, 0x5d, 0x79, 0x8d, 0x79, 0x8e, + 0x79, 0x40, 0x7a, 0x81, 0x7a, 0xc0, 0x7b, 0xf4, + 0x7d, 0x09, 0x7e, 0x41, 0x7e, 0x72, 0x7f, 0x05, + 0x80, 0xed, 0x81, 0x79, 0x82, 0x79, 0x82, 0x57, + 0x84, 0x10, 0x89, 0x96, 0x89, 0x01, 0x8b, 0x39, + 0x8b, 0xd3, 0x8c, 0x08, 0x8d, 0xb6, 0x8f, 0x38, + 0x90, 0xe3, 0x96, 0xff, 0x97, 0x3b, 0x98, 0x75, + 0x60, 0xee, 0x42, 0x18, 0x82, 0x02, 0x26, 0x4e, + 0xb5, 0x51, 0x68, 0x51, 0x80, 0x4f, 0x45, 0x51, + 0x80, 0x51, 0xc7, 0x52, 0xfa, 0x52, 0x9d, 0x55, + 0x55, 0x55, 0x99, 0x55, 0xe2, 0x55, 0x5a, 0x58, + 0xb3, 0x58, 0x44, 0x59, 0x54, 0x59, 0x62, 0x5a, + 0x28, 0x5b, 0xd2, 0x5e, 0xd9, 0x5e, 0x69, 0x5f, + 0xad, 0x5f, 0xd8, 0x60, 0x4e, 0x61, 0x08, 0x61, + 0x8e, 0x61, 0x60, 0x61, 0xf2, 0x61, 0x34, 0x62, + 0xc4, 0x63, 0x1c, 0x64, 0x52, 0x64, 0x56, 0x65, + 0x74, 0x66, 0x17, 0x67, 0x1b, 0x67, 0x56, 0x67, + 0x79, 0x6b, 0xba, 0x6b, 0x41, 0x6d, 0xdb, 0x6e, + 0xcb, 0x6e, 0x22, 0x6f, 0x1e, 0x70, 0x6e, 0x71, + 0xa7, 0x77, 0x35, 0x72, 0xaf, 0x72, 0x2a, 0x73, + 0x71, 0x74, 0x06, 0x75, 0x3b, 0x75, 0x1d, 0x76, + 0x1f, 0x76, 0xca, 0x76, 0xdb, 0x76, 0xf4, 0x76, + 0x4a, 0x77, 0x40, 0x77, 0xcc, 0x78, 0xb1, 0x7a, + 0xc0, 0x7b, 0x7b, 0x7c, 0x5b, 0x7d, 0xf4, 0x7d, + 0x3e, 0x7f, 0x05, 0x80, 0x52, 0x83, 0xef, 0x83, + 0x79, 0x87, 0x41, 0x89, 0x86, 0x89, 0x96, 0x89, + 0xbf, 0x8a, 0xf8, 0x8a, 0xcb, 0x8a, 0x01, 0x8b, + 0xfe, 0x8a, 0xed, 0x8a, 0x39, 0x8b, 0x8a, 0x8b, + 0x08, 0x8d, 0x38, 0x8f, 0x72, 0x90, 0x99, 0x91, + 0x76, 0x92, 0x7c, 0x96, 0xe3, 0x96, 0x56, 0x97, + 0xdb, 0x97, 0xff, 0x97, 0x0b, 0x98, 0x3b, 0x98, + 0x12, 0x9b, 0x9c, 0x9f, 0x4a, 0x28, 0x44, 0x28, + 0xd5, 0x33, 0x9d, 0x3b, 0x18, 0x40, 0x39, 0x40, + 0x49, 0x52, 0xd0, 0x5c, 0xd3, 0x7e, 0x43, 0x9f, + 0x8e, 0x9f, 0x2a, 0xa0, 0x02, 0x66, 0x66, 0x66, + 0x69, 0x66, 0x6c, 0x66, 0x66, 0x69, 0x66, 0x66, + 0x6c, 0x7f, 0x01, 0x74, 0x73, 0x00, 0x74, 0x65, + 0x05, 0x0f, 0x11, 0x0f, 0x00, 0x0f, 0x06, 0x19, + 0x11, 0x0f, 0x08, 0xd9, 0x05, 0xb4, 0x05, 0x00, + 0x00, 0x00, 0x00, 0xf2, 0x05, 0xb7, 0x05, 0xd0, + 0x05, 0x12, 0x00, 0x03, 0x04, 0x0b, 0x0c, 0x0d, + 0x18, 0x1a, 0xe9, 0x05, 0xc1, 0x05, 0xe9, 0x05, + 0xc2, 0x05, 0x49, 0xfb, 0xc1, 0x05, 0x49, 0xfb, + 0xc2, 0x05, 0xd0, 0x05, 0xb7, 0x05, 0xd0, 0x05, + 0xb8, 0x05, 0xd0, 0x05, 0xbc, 0x05, 0xd8, 0x05, + 0xbc, 0x05, 0xde, 0x05, 0xbc, 0x05, 0xe0, 0x05, + 0xbc, 0x05, 0xe3, 0x05, 0xbc, 0x05, 0xb9, 0x05, + 0x2d, 0x03, 0x2e, 0x03, 0x2f, 0x03, 0x30, 0x03, + 0x31, 0x03, 0x1c, 0x00, 0x18, 0x06, 0x22, 0x06, + 0x2b, 0x06, 0xd0, 0x05, 0xdc, 0x05, 0x71, 0x06, + 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x09, + 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, 0x08, 0x08, + 0x08, 0x08, 0x33, 0x33, 0x33, 0x33, 0x35, 0x35, + 0x35, 0x35, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, + 0x12, 0x12, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, + 0x16, 0x16, 0x1c, 0x1c, 0x1b, 0x1b, 0x1d, 0x1d, + 0x17, 0x17, 0x27, 0x27, 0x20, 0x20, 0x38, 0x38, + 0x38, 0x38, 0x3e, 0x3e, 0x3e, 0x3e, 0x42, 0x42, + 0x42, 0x42, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4f, 0x4f, 0x50, 0x50, + 0x50, 0x50, 0x4d, 0x4d, 0x4d, 0x4d, 0x61, 0x61, + 0x62, 0x62, 0x49, 0x06, 0x64, 0x64, 0x64, 0x64, + 0x7e, 0x7e, 0x7d, 0x7d, 0x7f, 0x7f, 0x2e, 0x82, + 0x82, 0x7c, 0x7c, 0x80, 0x80, 0x87, 0x87, 0x87, + 0x87, 0x00, 0x00, 0x26, 0x06, 0x00, 0x01, 0x00, + 0x01, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x22, 0x00, + 0x22, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0xa0, 0x00, + 0xa0, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xaa, 0x00, + 0xaa, 0x00, 0xaa, 0x00, 0x23, 0x00, 0x23, 0x00, + 0x23, 0xcc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x26, + 0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1f, 0x00, + 0x23, 0x00, 0x24, 0x02, 0x06, 0x02, 0x07, 0x02, + 0x08, 0x02, 0x1f, 0x02, 0x23, 0x02, 0x24, 0x04, + 0x06, 0x04, 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, + 0x23, 0x04, 0x24, 0x05, 0x06, 0x05, 0x1f, 0x05, + 0x23, 0x05, 0x24, 0x06, 0x07, 0x06, 0x1f, 0x07, + 0x06, 0x07, 0x1f, 0x08, 0x06, 0x08, 0x07, 0x08, + 0x1f, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x08, 0x0d, + 0x1f, 0x0f, 0x07, 0x0f, 0x1f, 0x10, 0x06, 0x10, + 0x07, 0x10, 0x08, 0x10, 0x1f, 0x11, 0x07, 0x11, + 0x1f, 0x12, 0x1f, 0x13, 0x06, 0x13, 0x1f, 0x14, + 0x06, 0x14, 0x1f, 0x1b, 0x06, 0x1b, 0x07, 0x1b, + 0x08, 0x1b, 0x1f, 0x1b, 0x23, 0x1b, 0x24, 0x1c, + 0x07, 0x1c, 0x1f, 0x1c, 0x23, 0x1c, 0x24, 0x1d, + 0x01, 0x1d, 0x06, 0x1d, 0x07, 0x1d, 0x08, 0x1d, + 0x1e, 0x1d, 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, + 0x06, 0x1e, 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, + 0x23, 0x1e, 0x24, 0x1f, 0x06, 0x1f, 0x07, 0x1f, + 0x08, 0x1f, 0x1f, 0x1f, 0x23, 0x1f, 0x24, 0x20, + 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20, + 0x23, 0x20, 0x24, 0x21, 0x06, 0x21, 0x1f, 0x21, + 0x23, 0x21, 0x24, 0x24, 0x06, 0x24, 0x07, 0x24, + 0x08, 0x24, 0x1f, 0x24, 0x23, 0x24, 0x24, 0x0a, + 0x4a, 0x0b, 0x4a, 0x23, 0x4a, 0x20, 0x00, 0x4c, + 0x06, 0x51, 0x06, 0x51, 0x06, 0xff, 0x00, 0x1f, + 0x26, 0x06, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x1f, + 0x00, 0x20, 0x00, 0x23, 0x00, 0x24, 0x02, 0x0b, + 0x02, 0x0c, 0x02, 0x1f, 0x02, 0x20, 0x02, 0x23, + 0x02, 0x24, 0x04, 0x0b, 0x04, 0x0c, 0x04, 0x1f, + 0x26, 0x06, 0x04, 0x20, 0x04, 0x23, 0x04, 0x24, + 0x05, 0x0b, 0x05, 0x0c, 0x05, 0x1f, 0x05, 0x20, + 0x05, 0x23, 0x05, 0x24, 0x1b, 0x23, 0x1b, 0x24, + 0x1c, 0x23, 0x1c, 0x24, 0x1d, 0x01, 0x1d, 0x1e, + 0x1d, 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x1f, + 0x1e, 0x23, 0x1e, 0x24, 0x1f, 0x01, 0x1f, 0x1f, + 0x20, 0x0b, 0x20, 0x0c, 0x20, 0x1f, 0x20, 0x20, + 0x20, 0x23, 0x20, 0x24, 0x23, 0x4a, 0x24, 0x0b, + 0x24, 0x0c, 0x24, 0x1f, 0x24, 0x20, 0x24, 0x23, + 0x24, 0x24, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, + 0x00, 0x1f, 0x00, 0x21, 0x02, 0x06, 0x02, 0x07, + 0x02, 0x08, 0x02, 0x1f, 0x02, 0x21, 0x04, 0x06, + 0x04, 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x21, + 0x05, 0x1f, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06, + 0x07, 0x1f, 0x08, 0x06, 0x08, 0x1f, 0x0d, 0x06, + 0x0d, 0x07, 0x0d, 0x08, 0x0d, 0x1f, 0x0f, 0x07, + 0x0f, 0x08, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07, + 0x10, 0x08, 0x10, 0x1f, 0x11, 0x07, 0x12, 0x1f, + 0x13, 0x06, 0x13, 0x1f, 0x14, 0x06, 0x14, 0x1f, + 0x1b, 0x06, 0x1b, 0x07, 0x1b, 0x08, 0x1b, 0x1f, + 0x1c, 0x07, 0x1c, 0x1f, 0x1d, 0x06, 0x1d, 0x07, + 0x1d, 0x08, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x06, + 0x1e, 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x21, + 0x1f, 0x06, 0x1f, 0x07, 0x1f, 0x08, 0x1f, 0x1f, + 0x20, 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, + 0x20, 0x21, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x4a, + 0x24, 0x06, 0x24, 0x07, 0x24, 0x08, 0x24, 0x1f, + 0x24, 0x21, 0x00, 0x1f, 0x00, 0x21, 0x02, 0x1f, + 0x02, 0x21, 0x04, 0x1f, 0x04, 0x21, 0x05, 0x1f, + 0x05, 0x21, 0x0d, 0x1f, 0x0d, 0x21, 0x0e, 0x1f, + 0x0e, 0x21, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x1f, + 0x20, 0x1f, 0x20, 0x21, 0x24, 0x1f, 0x24, 0x21, + 0x40, 0x06, 0x4e, 0x06, 0x51, 0x06, 0x27, 0x06, + 0x10, 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, + 0x13, 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, + 0x0d, 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, + 0x05, 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, + 0x0e, 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, + 0x0d, 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, + 0x0d, 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, + 0x10, 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, + 0x13, 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, + 0x0d, 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, + 0x05, 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, + 0x0e, 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, + 0x0d, 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, + 0x0d, 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, + 0x0d, 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, + 0x0c, 0x20, 0x0d, 0x20, 0x10, 0x1e, 0x0c, 0x05, + 0x0c, 0x06, 0x0c, 0x07, 0x0d, 0x05, 0x0d, 0x06, + 0x0d, 0x07, 0x10, 0x1e, 0x11, 0x1e, 0x00, 0x24, + 0x00, 0x24, 0x2a, 0x06, 0x00, 0x02, 0x1b, 0x00, + 0x03, 0x02, 0x00, 0x03, 0x02, 0x00, 0x03, 0x1b, + 0x00, 0x04, 0x1b, 0x00, 0x1b, 0x02, 0x00, 0x1b, + 0x03, 0x00, 0x1b, 0x04, 0x02, 0x1b, 0x03, 0x02, + 0x1b, 0x03, 0x03, 0x1b, 0x20, 0x03, 0x1b, 0x1f, + 0x09, 0x03, 0x02, 0x09, 0x02, 0x03, 0x09, 0x02, + 0x1f, 0x09, 0x1b, 0x03, 0x09, 0x1b, 0x03, 0x09, + 0x1b, 0x02, 0x09, 0x1b, 0x1b, 0x09, 0x1b, 0x1b, + 0x0b, 0x03, 0x03, 0x0b, 0x03, 0x03, 0x0b, 0x1b, + 0x1b, 0x0a, 0x03, 0x1b, 0x0a, 0x03, 0x1b, 0x0a, + 0x02, 0x20, 0x0a, 0x1b, 0x04, 0x0a, 0x1b, 0x04, + 0x0a, 0x1b, 0x1b, 0x0a, 0x1b, 0x1b, 0x0c, 0x03, + 0x1f, 0x0c, 0x04, 0x1b, 0x0c, 0x04, 0x1b, 0x0d, + 0x1b, 0x03, 0x0d, 0x1b, 0x03, 0x0d, 0x1b, 0x1b, + 0x0d, 0x1b, 0x20, 0x0f, 0x02, 0x1b, 0x0f, 0x1b, + 0x1b, 0x0f, 0x1b, 0x1b, 0x0f, 0x1b, 0x1f, 0x10, + 0x1b, 0x1b, 0x10, 0x1b, 0x20, 0x10, 0x1b, 0x1f, + 0x17, 0x04, 0x1b, 0x17, 0x04, 0x1b, 0x18, 0x1b, + 0x03, 0x18, 0x1b, 0x1b, 0x1a, 0x03, 0x1b, 0x1a, + 0x03, 0x20, 0x1a, 0x03, 0x1f, 0x1a, 0x02, 0x02, + 0x1a, 0x02, 0x02, 0x1a, 0x04, 0x1b, 0x1a, 0x04, + 0x1b, 0x1a, 0x1b, 0x03, 0x1a, 0x1b, 0x03, 0x1b, + 0x03, 0x02, 0x1b, 0x03, 0x1b, 0x1b, 0x03, 0x20, + 0x1b, 0x02, 0x03, 0x1b, 0x02, 0x1b, 0x1b, 0x04, + 0x02, 0x1b, 0x04, 0x1b, 0x28, 0x06, 0x1d, 0x04, + 0x06, 0x1f, 0x1d, 0x04, 0x1f, 0x1d, 0x1d, 0x1e, + 0x05, 0x1d, 0x1e, 0x05, 0x21, 0x1e, 0x04, 0x1d, + 0x1e, 0x04, 0x1d, 0x1e, 0x04, 0x21, 0x1e, 0x1d, + 0x22, 0x1e, 0x1d, 0x21, 0x22, 0x1d, 0x1d, 0x22, + 0x1d, 0x1d, 0x00, 0x06, 0x22, 0x02, 0x04, 0x22, + 0x02, 0x04, 0x21, 0x02, 0x06, 0x22, 0x02, 0x06, + 0x21, 0x02, 0x1d, 0x22, 0x02, 0x1d, 0x21, 0x04, + 0x1d, 0x22, 0x04, 0x05, 0x21, 0x04, 0x1d, 0x21, + 0x0b, 0x06, 0x21, 0x0d, 0x05, 0x22, 0x0c, 0x05, + 0x22, 0x0e, 0x05, 0x22, 0x1c, 0x04, 0x22, 0x1c, + 0x1d, 0x22, 0x22, 0x05, 0x22, 0x22, 0x04, 0x22, + 0x22, 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1a, 0x1d, + 0x22, 0x1e, 0x05, 0x22, 0x1a, 0x1d, 0x05, 0x1c, + 0x05, 0x1d, 0x11, 0x1d, 0x22, 0x1b, 0x1d, 0x22, + 0x1e, 0x04, 0x05, 0x1d, 0x06, 0x22, 0x1c, 0x04, + 0x1d, 0x1b, 0x1d, 0x1d, 0x1c, 0x04, 0x1d, 0x1e, + 0x04, 0x05, 0x04, 0x05, 0x22, 0x05, 0x04, 0x22, + 0x1d, 0x04, 0x22, 0x19, 0x1d, 0x22, 0x00, 0x05, + 0x22, 0x1b, 0x1d, 0x1d, 0x11, 0x04, 0x1d, 0x0d, + 0x1d, 0x1d, 0x0b, 0x06, 0x22, 0x1e, 0x04, 0x22, + 0x35, 0x06, 0x00, 0x0f, 0x9d, 0x0d, 0x0f, 0x9d, + 0x27, 0x06, 0x00, 0x1d, 0x1d, 0x20, 0x00, 0x1c, + 0x01, 0x0a, 0x1e, 0x06, 0x1e, 0x08, 0x0e, 0x1d, + 0x12, 0x1e, 0x0a, 0x0c, 0x21, 0x1d, 0x12, 0x1d, + 0x23, 0x20, 0x21, 0x0c, 0x1d, 0x1e, 0x35, 0x06, + 0x00, 0x0f, 0x14, 0x27, 0x06, 0x0e, 0x1d, 0x22, + 0xff, 0x00, 0x1d, 0x1d, 0x20, 0xff, 0x12, 0x1d, + 0x23, 0x20, 0xff, 0x21, 0x0c, 0x1d, 0x1e, 0x27, + 0x06, 0x05, 0x1d, 0xff, 0x05, 0x1d, 0x00, 0x1d, + 0x20, 0x27, 0x06, 0x0a, 0xa5, 0x00, 0x1d, 0x2c, + 0x00, 0x01, 0x30, 0x02, 0x30, 0x3a, 0x00, 0x3b, + 0x00, 0x21, 0x00, 0x3f, 0x00, 0x16, 0x30, 0x17, + 0x30, 0x26, 0x20, 0x13, 0x20, 0x12, 0x01, 0x00, + 0x5f, 0x5f, 0x28, 0x29, 0x7b, 0x7d, 0x08, 0x30, + 0x0c, 0x0d, 0x08, 0x09, 0x02, 0x03, 0x00, 0x01, + 0x04, 0x05, 0x06, 0x07, 0x5b, 0x00, 0x5d, 0x00, + 0x3e, 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x3e, 0x20, + 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x2c, 0x00, + 0x01, 0x30, 0x2e, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x3a, 0x00, 0x3f, 0x00, 0x21, 0x00, 0x14, 0x20, + 0x28, 0x00, 0x29, 0x00, 0x7b, 0x00, 0x7d, 0x00, + 0x14, 0x30, 0x15, 0x30, 0x23, 0x26, 0x2a, 0x2b, + 0x2d, 0x3c, 0x3e, 0x3d, 0x00, 0x5c, 0x24, 0x25, + 0x40, 0x40, 0x06, 0xff, 0x0b, 0x00, 0x0b, 0xff, + 0x0c, 0x20, 0x00, 0x4d, 0x06, 0x40, 0x06, 0xff, + 0x0e, 0x00, 0x0e, 0xff, 0x0f, 0x00, 0x0f, 0xff, + 0x10, 0x00, 0x10, 0xff, 0x11, 0x00, 0x11, 0xff, + 0x12, 0x00, 0x12, 0x21, 0x06, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, + 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, + 0x0f, 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, + 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, + 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x20, 0x20, + 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, + 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, + 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, + 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, + 0x29, 0x29, 0x22, 0x06, 0x22, 0x00, 0x22, 0x00, + 0x22, 0x01, 0x22, 0x01, 0x22, 0x03, 0x22, 0x03, + 0x22, 0x05, 0x22, 0x05, 0x21, 0x00, 0x85, 0x29, + 0x01, 0x30, 0x01, 0x0b, 0x0c, 0x00, 0xfa, 0xf1, + 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xe2, 0xe4, 0xe6, + 0xc2, 0xfb, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, + 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, + 0xbc, 0xbe, 0xc0, 0xc3, 0xc5, 0xc7, 0xc9, 0xca, + 0xcb, 0xcc, 0xcd, 0xce, 0xd1, 0xd4, 0xd7, 0xda, + 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe3, 0xe5, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xee, 0xf2, 0x98, + 0x99, 0x31, 0x31, 0x4f, 0x31, 0x55, 0x31, 0x5b, + 0x31, 0x61, 0x31, 0xa2, 0x00, 0xa3, 0x00, 0xac, + 0x00, 0xaf, 0x00, 0xa6, 0x00, 0xa5, 0x00, 0xa9, + 0x20, 0x00, 0x00, 0x02, 0x25, 0x90, 0x21, 0x91, + 0x21, 0x92, 0x21, 0x93, 0x21, 0xa0, 0x25, 0xcb, + 0x25, 0xd2, 0x05, 0x07, 0x03, 0x01, 0xda, 0x05, + 0x07, 0x03, 0x01, 0xd0, 0x02, 0xd1, 0x02, 0xe6, + 0x00, 0x99, 0x02, 0x53, 0x02, 0x00, 0x00, 0xa3, + 0x02, 0x66, 0xab, 0xa5, 0x02, 0xa4, 0x02, 0x56, + 0x02, 0x57, 0x02, 0x91, 0x1d, 0x58, 0x02, 0x5e, + 0x02, 0xa9, 0x02, 0x64, 0x02, 0x62, 0x02, 0x60, + 0x02, 0x9b, 0x02, 0x27, 0x01, 0x9c, 0x02, 0x67, + 0x02, 0x84, 0x02, 0xaa, 0x02, 0xab, 0x02, 0x6c, + 0x02, 0x04, 0xdf, 0x8e, 0xa7, 0x6e, 0x02, 0x05, + 0xdf, 0x8e, 0x02, 0x06, 0xdf, 0xf8, 0x00, 0x76, + 0x02, 0x77, 0x02, 0x71, 0x00, 0x7a, 0x02, 0x08, + 0xdf, 0x7d, 0x02, 0x7e, 0x02, 0x80, 0x02, 0xa8, + 0x02, 0xa6, 0x02, 0x67, 0xab, 0xa7, 0x02, 0x88, + 0x02, 0x71, 0x2c, 0x00, 0x00, 0x8f, 0x02, 0xa1, + 0x02, 0xa2, 0x02, 0x98, 0x02, 0xc0, 0x01, 0xc1, + 0x01, 0xc2, 0x01, 0x0a, 0xdf, 0x1e, 0xdf, 0x41, + 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x14, 0x99, + 0x10, 0xba, 0x10, 0x00, 0x00, 0x00, 0x00, 0x9b, + 0x10, 0xba, 0x10, 0x05, 0x05, 0xa5, 0x10, 0xba, + 0x10, 0x05, 0x31, 0x11, 0x27, 0x11, 0x32, 0x11, + 0x27, 0x11, 0x55, 0x47, 0x13, 0x3e, 0x13, 0x47, + 0x13, 0x57, 0x13, 0x55, 0x82, 0x13, 0xc9, 0x13, + 0x00, 0x00, 0x00, 0x00, 0x84, 0x13, 0xbb, 0x13, + 0x05, 0x05, 0x8b, 0x13, 0xc2, 0x13, 0x05, 0x90, + 0x13, 0xc9, 0x13, 0x05, 0xc2, 0x13, 0xc2, 0x13, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0x13, 0xb8, 0x13, + 0xc2, 0x13, 0xc9, 0x13, 0x05, 0x55, 0xb9, 0x14, + 0xba, 0x14, 0xb9, 0x14, 0xb0, 0x14, 0x00, 0x00, + 0x00, 0x00, 0xb9, 0x14, 0xbd, 0x14, 0x55, 0x50, + 0xb8, 0x15, 0xaf, 0x15, 0xb9, 0x15, 0xaf, 0x15, + 0x55, 0x35, 0x19, 0x30, 0x19, 0x05, 0x1e, 0x61, + 0x1e, 0x61, 0x1e, 0x61, 0x29, 0x61, 0x1e, 0x61, + 0x1f, 0x61, 0x29, 0x61, 0x1f, 0x61, 0x1e, 0x61, + 0x20, 0x61, 0x21, 0x61, 0x1f, 0x61, 0x22, 0x61, + 0x1f, 0x61, 0x21, 0x61, 0x20, 0x61, 0x55, 0x55, + 0x55, 0x55, 0x67, 0x6d, 0x67, 0x6d, 0x63, 0x6d, + 0x67, 0x6d, 0x69, 0x6d, 0x67, 0x6d, 0x55, 0x05, + 0x41, 0x00, 0x30, 0x00, 0x57, 0xd1, 0x65, 0xd1, + 0x58, 0xd1, 0x65, 0xd1, 0x5f, 0xd1, 0x6e, 0xd1, + 0x5f, 0xd1, 0x6f, 0xd1, 0x5f, 0xd1, 0x70, 0xd1, + 0x5f, 0xd1, 0x71, 0xd1, 0x5f, 0xd1, 0x72, 0xd1, + 0x55, 0x55, 0x55, 0x05, 0xb9, 0xd1, 0x65, 0xd1, + 0xba, 0xd1, 0x65, 0xd1, 0xbb, 0xd1, 0x6e, 0xd1, + 0xbc, 0xd1, 0x6e, 0xd1, 0xbb, 0xd1, 0x6f, 0xd1, + 0xbc, 0xd1, 0x6f, 0xd1, 0x55, 0x55, 0x55, 0x41, + 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x69, + 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x43, + 0x44, 0x00, 0x00, 0x47, 0x00, 0x00, 0x4a, 0x4b, + 0x00, 0x00, 0x4e, 0x4f, 0x50, 0x51, 0x00, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, + 0x62, 0x63, 0x64, 0x00, 0x66, 0x68, 0x00, 0x70, + 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x42, 0x00, + 0x44, 0x45, 0x46, 0x47, 0x4a, 0x00, 0x53, 0x00, + 0x61, 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, 0x46, + 0x47, 0x00, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, + 0x4f, 0x53, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, + 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, + 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, + 0x00, 0x41, 0x00, 0x61, 0x00, 0x31, 0x01, 0x37, + 0x02, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, + 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, + 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, + 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, + 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, + 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, + 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, + 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, + 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x0b, + 0x0c, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, + 0x00, 0x30, 0x00, 0x30, 0x04, 0x3a, 0x04, 0x3e, + 0x04, 0x4b, 0x04, 0x4d, 0x04, 0x4e, 0x04, 0x89, + 0xa6, 0x30, 0x04, 0xa9, 0x26, 0x28, 0xb9, 0x7f, + 0x9f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x0f, 0x11, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x61, + 0x26, 0x25, 0x2f, 0x7b, 0x51, 0xa6, 0xb1, 0x04, + 0x27, 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, 0x06, + 0x1e, 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, 0x1b, + 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, + 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x44, + 0x90, 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, 0x00, + 0x00, 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, 0x11, + 0x12, 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, 0x34, + 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00, + 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x2d, + 0x06, 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x44, + 0x06, 0x00, 0x00, 0x46, 0x06, 0x33, 0x06, 0x39, + 0x06, 0x00, 0x00, 0x35, 0x06, 0x42, 0x06, 0x00, + 0x00, 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2e, + 0x06, 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, + 0x06, 0x00, 0x00, 0xba, 0x06, 0x00, 0x00, 0x6f, + 0x06, 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06, 0x00, + 0x00, 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2d, + 0x06, 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06, 0x00, + 0x00, 0x45, 0x06, 0x46, 0x06, 0x33, 0x06, 0x39, + 0x06, 0x41, 0x06, 0x35, 0x06, 0x42, 0x06, 0x00, + 0x00, 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, + 0x06, 0x00, 0x00, 0x36, 0x06, 0x38, 0x06, 0x3a, + 0x06, 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06, 0x27, + 0x06, 0x00, 0x01, 0x05, 0x08, 0x20, 0x21, 0x0b, + 0x06, 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, 0x1c, + 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, + 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28, 0x06, + 0x2c, 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48, 0x06, + 0x32, 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06, + 0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17, + 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06, + 0x0c, 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00, 0x2c, + 0x00, 0x28, 0x00, 0x41, 0x00, 0x29, 0x00, 0x14, + 0x30, 0x53, 0x00, 0x15, 0x30, 0x43, 0x52, 0x43, + 0x44, 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56, 0x4d, + 0x56, 0x53, 0x44, 0x53, 0x53, 0x50, 0x50, 0x56, + 0x57, 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d, 0x52, + 0x44, 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68, 0x68, + 0x4b, 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7, 0x30, + 0x8c, 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29, 0x59, + 0xa4, 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99, 0x65, + 0x4d, 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0, 0x65, + 0x1d, 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9, 0x8c, + 0xf0, 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95, 0x62, + 0x55, 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a, 0x90, + 0xe6, 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07, 0x63, + 0x70, 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a, 0x7a, + 0x08, 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08, 0x67, + 0x33, 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d, 0x91, + 0x14, 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09, 0x4e, + 0x8c, 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53, 0x62, + 0xd7, 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97, 0x5f, + 0xef, 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05, 0x00, + 0x09, 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f, 0xbb, + 0x4f, 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50, 0xe7, + 0x50, 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06, 0x4d, + 0x51, 0x54, 0x51, 0x64, 0x51, 0x77, 0x51, 0x1c, + 0x05, 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51, 0x4b, + 0x05, 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e, 0xac, + 0x51, 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51, 0x03, + 0x52, 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52, 0x72, + 0x52, 0x77, 0x52, 0x15, 0x35, 0x02, 0x00, 0x20, + 0x80, 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7, 0x52, + 0x00, 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50, 0x82, + 0x8a, 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8, 0x2c, + 0x0a, 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53, 0x63, + 0x0b, 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54, 0x9e, + 0x54, 0x38, 0x54, 0x48, 0x54, 0x68, 0x54, 0xa2, + 0x54, 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55, 0x63, + 0x55, 0x84, 0x55, 0x84, 0x55, 0x99, 0x55, 0xab, + 0x55, 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57, 0x06, + 0x56, 0x17, 0x57, 0x51, 0x56, 0x74, 0x56, 0x07, + 0x52, 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57, 0x0d, + 0x58, 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58, 0xac, + 0x58, 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58, 0x06, + 0x59, 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59, 0xa8, + 0x16, 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a, 0x27, + 0x5a, 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36, 0xfc, + 0x36, 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b, 0xc8, + 0x19, 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b, 0xf3, + 0x5b, 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c, 0x53, + 0x5f, 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c, 0x6e, + 0x5c, 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d, 0x43, + 0x5d, 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d, 0x7c, + 0x5d, 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38, 0xfd, + 0x5d, 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e, 0x62, + 0x38, 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e, 0xb3, + 0x5e, 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3, 0xfe, + 0x5e, 0x31, 0x23, 0x31, 0x23, 0x01, 0x82, 0x22, + 0x5f, 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32, 0xda, + 0x61, 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38, 0x9a, + 0x5f, 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f, 0x81, + 0x60, 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60, 0xd4, + 0x26, 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, + 0x00, 0x02, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00, + 0x08, 0x80, 0x28, 0x80, 0x02, 0x00, 0x00, 0x02, + 0x48, 0x61, 0x00, 0x04, 0x06, 0x04, 0x32, 0x46, + 0x6a, 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8, 0xd3, + 0x5d, 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c, 0x2b, + 0x3d, 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83, 0x63, + 0xe4, 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5, 0x63, + 0xa9, 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e, 0x64, + 0x9d, 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f, 0x65, + 0x6c, 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8, 0x66, + 0x49, 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08, 0x3b, + 0xe4, 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00, 0x67, + 0x9c, 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17, 0x67, + 0x1b, 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53, 0x67, + 0xc3, 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85, 0x67, + 0x52, 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e, 0x68, + 0x1f, 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42, 0x69, + 0xa3, 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3, 0x36, + 0xdb, 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7, 0x38, + 0x54, 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f, 0x6b, + 0xba, 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b, 0x1d, + 0xfa, 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf, 0x6c, + 0xcd, 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e, 0x6d, + 0x77, 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78, 0x6d, + 0x85, 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f, 0x6e, + 0x6e, 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7, 0x6e, + 0xd1, 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e, 0x3f, + 0x8e, 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e, 0x70, + 0x1b, 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d, 0x70, + 0x77, 0x70, 0xad, 0x70, 0x25, 0x05, 0x45, 0x71, + 0x63, 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28, 0x72, + 0x35, 0x72, 0x50, 0x72, 0x08, 0x46, 0x80, 0x72, + 0x95, 0x72, 0x35, 0x47, 0x02, 0x20, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, + 0x00, 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00, 0x20, + 0x00, 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80, 0x20, + 0x14, 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac, 0x3e, + 0xa5, 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47, 0x74, + 0x5c, 0x74, 0x71, 0x74, 0x85, 0x74, 0xca, 0x74, + 0x1b, 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e, 0x75, + 0x92, 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10, 0x76, + 0xa1, 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc, 0x3f, + 0x08, 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2, 0x50, + 0x19, 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f, 0x77, + 0x1f, 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b, 0x77, + 0x46, 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e, 0x78, + 0x8c, 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26, 0x56, + 0x56, 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f, 0x79, + 0xeb, 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a, 0x7a, + 0x4f, 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7, 0x5a, + 0xee, 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6, 0x7b, + 0xc9, 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2, 0x7c, + 0xa0, 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00, 0x7d, + 0x86, 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7, 0x7d, + 0x02, 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28, 0x62, + 0x47, 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a, 0x7f, + 0x3e, 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05, 0x80, + 0xda, 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8, 0x65, + 0x70, 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2, 0x80, + 0x03, 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5, 0x5a, + 0xa7, 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c, 0x33, + 0x01, 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b, 0x44, + 0x91, 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3, 0x52, + 0xb1, 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6, 0x82, + 0x3c, 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63, 0x83, + 0xad, 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7, 0x83, + 0x57, 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc, 0x83, + 0xdc, 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02, 0x00, + 0x00, 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00, 0x20, + 0x80, 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00, 0x02, + 0x80, 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5, 0x6c, + 0x2b, 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16, 0x85, + 0xca, 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d, 0x45, + 0x61, 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b, 0x45, + 0x50, 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69, 0x86, + 0xa9, 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2, 0x86, + 0x79, 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86, 0x87, + 0xd7, 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9, 0x45, + 0x60, 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7, 0x88, + 0xde, 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb, 0x34, + 0xae, 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7, 0x46, + 0xa0, 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55, 0x8c, + 0xa8, 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b, 0x8d, + 0x77, 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb, 0x8d, + 0xbc, 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4, 0x8e, + 0x38, 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94, 0x90, + 0xf1, 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b, 0x91, + 0x38, 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c, 0x92, + 0xf9, 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b, 0x95, + 0x95, 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6, 0x49, + 0xc3, 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45, 0x91, + 0x1a, 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0, 0x97, + 0x0a, 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b, 0x98, + 0x0b, 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2, 0x98, + 0x33, 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2, 0x99, + 0xfe, 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12, 0x9b, + 0x40, 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed, 0x4c, + 0x67, 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05, 0xa1, + 0x0e, 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56, 0x4d, + 0xf9, 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f, 0x9f, + 0x16, 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02, 0x88, + 0xa0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x28, + 0x00, 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00, 0x80, + 0x80, 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80, 0x00, + 0x20, 0x2a, 0x00, 0x80, +}; + +static const uint16_t unicode_comp_table[965] = { + 0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0, + 0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982, + 0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8, + 0x02ca, 0x02cc, 0x0287, 0x228a, 0x02ce, 0x228c, 0x2290, 0x2292, + 0x228e, 0x0288, 0x0289, 0x028a, 0x2482, 0x0300, 0x0302, 0x0304, + 0x028b, 0x2480, 0x0308, 0x0984, 0x0986, 0x2458, 0x0a02, 0x0306, + 0x2298, 0x229a, 0x229e, 0x0900, 0x030a, 0x22a0, 0x030c, 0x030e, + 0x0840, 0x0310, 0x0312, 0x22a2, 0x22a6, 0x09c0, 0x22a4, 0x22a8, + 0x22aa, 0x028c, 0x028d, 0x028e, 0x0340, 0x0342, 0x0344, 0x0380, + 0x028f, 0x248e, 0x07c2, 0x0988, 0x098a, 0x2490, 0x0346, 0x22ac, + 0x0400, 0x22b0, 0x0842, 0x22b2, 0x0402, 0x22b4, 0x0440, 0x0444, + 0x22b6, 0x0442, 0x22c2, 0x22c0, 0x22c4, 0x22c6, 0x22c8, 0x0940, + 0x04c0, 0x0291, 0x22ca, 0x04c4, 0x22cc, 0x04c2, 0x22d0, 0x22ce, + 0x0292, 0x0293, 0x0294, 0x0295, 0x0540, 0x0542, 0x0a08, 0x0296, + 0x2494, 0x0544, 0x07c4, 0x098c, 0x098e, 0x06c0, 0x2492, 0x0844, + 0x2308, 0x230a, 0x0580, 0x230c, 0x0584, 0x0990, 0x0992, 0x230e, + 0x0582, 0x2312, 0x0586, 0x0588, 0x2314, 0x058c, 0x2316, 0x0998, + 0x058a, 0x231e, 0x0590, 0x2320, 0x099a, 0x058e, 0x2324, 0x2322, + 0x0299, 0x029a, 0x029b, 0x05c0, 0x05c2, 0x05c4, 0x029c, 0x24ac, + 0x05c6, 0x05c8, 0x07c6, 0x0994, 0x0996, 0x0700, 0x24aa, 0x2326, + 0x05ca, 0x232a, 0x2328, 0x2340, 0x2342, 0x2344, 0x2346, 0x05cc, + 0x234a, 0x2348, 0x234c, 0x234e, 0x2350, 0x24b8, 0x029d, 0x05ce, + 0x24be, 0x0a0c, 0x2352, 0x0600, 0x24bc, 0x24ba, 0x0640, 0x2354, + 0x0642, 0x0644, 0x2356, 0x2358, 0x02a0, 0x02a1, 0x02a2, 0x02a3, + 0x02c1, 0x02c3, 0x0a01, 0x02a4, 0x2443, 0x02a5, 0x07c1, 0x0981, + 0x0983, 0x2441, 0x2281, 0x02c5, 0x2283, 0x2285, 0x2287, 0x02c7, + 0x02c9, 0x02cb, 0x02cd, 0x02a7, 0x228b, 0x02cf, 0x228d, 0x2291, + 0x2293, 0x228f, 0x02a8, 0x02a9, 0x02aa, 0x2483, 0x0301, 0x0303, + 0x0305, 0x02ab, 0x2481, 0x0309, 0x0985, 0x0987, 0x2459, 0x0a03, + 0x0307, 0x2299, 0x229b, 0x229f, 0x0901, 0x030b, 0x22a1, 0x030d, + 0x030f, 0x0841, 0x0311, 0x0313, 0x22a3, 0x22a7, 0x09c1, 0x22a5, + 0x22a9, 0x22ab, 0x2380, 0x02ac, 0x02ad, 0x02ae, 0x0341, 0x0343, + 0x0345, 0x02af, 0x248f, 0x07c3, 0x0989, 0x098b, 0x2491, 0x0347, + 0x22ad, 0x0401, 0x0884, 0x22b1, 0x0843, 0x22b3, 0x0403, 0x22b5, + 0x0441, 0x0445, 0x22b7, 0x0443, 0x22c3, 0x22c1, 0x22c5, 0x22c7, + 0x22c9, 0x0941, 0x04c1, 0x02b1, 0x22cb, 0x04c5, 0x22cd, 0x04c3, + 0x22d1, 0x22cf, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x0541, 0x0543, + 0x0a09, 0x02b6, 0x2495, 0x0545, 0x07c5, 0x098d, 0x098f, 0x06c1, + 0x2493, 0x0845, 0x2309, 0x230b, 0x0581, 0x230d, 0x0585, 0x0991, + 0x0993, 0x230f, 0x0583, 0x2313, 0x0587, 0x0589, 0x2315, 0x058d, + 0x2317, 0x0999, 0x058b, 0x231f, 0x2381, 0x0591, 0x2321, 0x099b, + 0x058f, 0x2325, 0x2323, 0x02b9, 0x02ba, 0x02bb, 0x05c1, 0x05c3, + 0x05c5, 0x02bc, 0x24ad, 0x05c7, 0x05c9, 0x07c7, 0x0995, 0x0997, + 0x0701, 0x24ab, 0x2327, 0x05cb, 0x232b, 0x2329, 0x2341, 0x2343, + 0x2345, 0x2347, 0x05cd, 0x234b, 0x2349, 0x2382, 0x234d, 0x234f, + 0x2351, 0x24b9, 0x02bd, 0x05cf, 0x24bf, 0x0a0d, 0x2353, 0x02bf, + 0x24bd, 0x2383, 0x24bb, 0x0641, 0x2355, 0x0643, 0x0645, 0x2357, + 0x2359, 0x3101, 0x0c80, 0x2e00, 0x2446, 0x2444, 0x244a, 0x2448, + 0x0800, 0x0942, 0x0944, 0x0804, 0x2288, 0x2486, 0x2484, 0x248a, + 0x2488, 0x22ae, 0x2498, 0x2496, 0x249c, 0x249a, 0x2300, 0x0a06, + 0x2302, 0x0a04, 0x0946, 0x07ce, 0x07ca, 0x07c8, 0x07cc, 0x2447, + 0x2445, 0x244b, 0x2449, 0x0801, 0x0943, 0x0945, 0x0805, 0x2289, + 0x2487, 0x2485, 0x248b, 0x2489, 0x22af, 0x2499, 0x2497, 0x249d, + 0x249b, 0x2301, 0x0a07, 0x2303, 0x0a05, 0x0947, 0x07cf, 0x07cb, + 0x07c9, 0x07cd, 0x2450, 0x244e, 0x2454, 0x2452, 0x2451, 0x244f, + 0x2455, 0x2453, 0x2294, 0x2296, 0x2295, 0x2297, 0x2304, 0x2306, + 0x2305, 0x2307, 0x2318, 0x2319, 0x231a, 0x231b, 0x232c, 0x232d, + 0x232e, 0x232f, 0x2400, 0x24a2, 0x24a0, 0x24a6, 0x24a4, 0x24a8, + 0x24a3, 0x24a1, 0x24a7, 0x24a5, 0x24a9, 0x24b0, 0x24ae, 0x24b4, + 0x24b2, 0x24b6, 0x24b1, 0x24af, 0x24b5, 0x24b3, 0x24b7, 0x0882, + 0x0880, 0x0881, 0x0802, 0x0803, 0x229c, 0x229d, 0x0a0a, 0x0a0b, + 0x0883, 0x0b40, 0x2c8a, 0x0c81, 0x2c89, 0x2c88, 0x2540, 0x2541, + 0x2d00, 0x2e07, 0x0d00, 0x2640, 0x2641, 0x2e80, 0x0d01, 0x26c8, + 0x26c9, 0x2f00, 0x2f84, 0x0d02, 0x2f83, 0x2f82, 0x0d40, 0x26d8, + 0x26d9, 0x3186, 0x0d04, 0x2740, 0x2741, 0x3100, 0x3086, 0x0d06, + 0x3085, 0x3084, 0x0d41, 0x2840, 0x3200, 0x0d07, 0x284f, 0x2850, + 0x3280, 0x2c84, 0x2e03, 0x2857, 0x0d42, 0x2c81, 0x2c80, 0x24c0, + 0x24c1, 0x2c86, 0x2c83, 0x28c0, 0x0d43, 0x25c0, 0x25c1, 0x2940, + 0x0d44, 0x26c0, 0x26c1, 0x2e05, 0x2e02, 0x29c0, 0x0d45, 0x2f05, + 0x2f04, 0x0d80, 0x26d0, 0x26d1, 0x2f80, 0x2a40, 0x0d82, 0x26e0, + 0x26e1, 0x3080, 0x3081, 0x2ac0, 0x0d83, 0x3004, 0x3003, 0x0d81, + 0x27c0, 0x27c1, 0x3082, 0x2b40, 0x0d84, 0x2847, 0x2848, 0x3184, + 0x3181, 0x2f06, 0x0d08, 0x2f81, 0x3005, 0x0d46, 0x3083, 0x3182, + 0x0e00, 0x0e01, 0x0f40, 0x1180, 0x1182, 0x0f03, 0x0f00, 0x11c0, + 0x0f01, 0x1140, 0x1202, 0x1204, 0x0f81, 0x1240, 0x0fc0, 0x1242, + 0x0f80, 0x1244, 0x1284, 0x0f82, 0x1286, 0x1288, 0x128a, 0x12c0, + 0x1282, 0x1181, 0x1183, 0x1043, 0x1040, 0x11c1, 0x1041, 0x1141, + 0x1203, 0x1205, 0x10c1, 0x1241, 0x1000, 0x1243, 0x10c0, 0x1245, + 0x1285, 0x10c2, 0x1287, 0x1289, 0x128b, 0x12c1, 0x1283, 0x1080, + 0x1100, 0x1101, 0x1200, 0x1201, 0x1280, 0x1281, 0x1340, 0x1341, + 0x1343, 0x1342, 0x1344, 0x13c2, 0x1400, 0x13c0, 0x1440, 0x1480, + 0x14c0, 0x1540, 0x1541, 0x1740, 0x1700, 0x1741, 0x17c0, 0x1800, + 0x1802, 0x1801, 0x1840, 0x1880, 0x1900, 0x18c0, 0x18c1, 0x1901, + 0x1940, 0x1942, 0x1941, 0x1980, 0x19c0, 0x19c2, 0x19c1, 0x1c80, + 0x1cc0, 0x1dc0, 0x1f80, 0x2000, 0x2002, 0x2004, 0x2006, 0x2008, + 0x2040, 0x2080, 0x2082, 0x20c0, 0x20c1, 0x2100, 0x22b8, 0x22b9, + 0x2310, 0x2311, 0x231c, 0x231d, 0x244c, 0x2456, 0x244d, 0x2457, + 0x248c, 0x248d, 0x249e, 0x249f, 0x2500, 0x2502, 0x2504, 0x2bc0, + 0x2501, 0x2503, 0x2505, 0x2bc1, 0x2bc2, 0x2bc3, 0x2bc4, 0x2bc5, + 0x2bc6, 0x2bc7, 0x2580, 0x2582, 0x2584, 0x2bc8, 0x2581, 0x2583, + 0x2585, 0x2bc9, 0x2bca, 0x2bcb, 0x2bcc, 0x2bcd, 0x2bce, 0x2bcf, + 0x2600, 0x2602, 0x2601, 0x2603, 0x2680, 0x2682, 0x2681, 0x2683, + 0x26c2, 0x26c4, 0x26c6, 0x2c00, 0x26c3, 0x26c5, 0x26c7, 0x2c01, + 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x26ca, 0x26cc, + 0x26ce, 0x2c08, 0x26cb, 0x26cd, 0x26cf, 0x2c09, 0x2c0a, 0x2c0b, + 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x26d2, 0x26d4, 0x26d6, 0x26d3, + 0x26d5, 0x26d7, 0x26da, 0x26dc, 0x26de, 0x26db, 0x26dd, 0x26df, + 0x2700, 0x2702, 0x2701, 0x2703, 0x2780, 0x2782, 0x2781, 0x2783, + 0x2800, 0x2802, 0x2804, 0x2801, 0x2803, 0x2805, 0x2842, 0x2844, + 0x2846, 0x2849, 0x284b, 0x284d, 0x2c40, 0x284a, 0x284c, 0x284e, + 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2851, + 0x2853, 0x2855, 0x2c48, 0x2852, 0x2854, 0x2856, 0x2c49, 0x2c4a, + 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c82, 0x2e01, 0x3180, + 0x2c87, 0x2f01, 0x2f02, 0x2f03, 0x2e06, 0x3185, 0x3000, 0x3001, + 0x3002, 0x4640, 0x4641, 0x4680, 0x46c0, 0x46c2, 0x46c1, 0x4700, + 0x4740, 0x4780, 0x47c0, 0x47c2, 0x4900, 0x4940, 0x4980, 0x4982, + 0x4a00, 0x49c2, 0x4a03, 0x4a04, 0x4a40, 0x4a41, 0x4a80, 0x4a81, + 0x4ac0, 0x4ac1, 0x4bc0, 0x4bc1, 0x4b00, 0x4b01, 0x4b40, 0x4b41, + 0x4bc2, 0x4bc3, 0x4b80, 0x4b81, 0x4b82, 0x4b83, 0x4c00, 0x4c01, + 0x4c02, 0x4c03, 0x5600, 0x5440, 0x5442, 0x5444, 0x5446, 0x5448, + 0x544a, 0x544c, 0x544e, 0x5450, 0x5452, 0x5454, 0x5456, 0x5480, + 0x5482, 0x5484, 0x54c0, 0x54c1, 0x5500, 0x5501, 0x5540, 0x5541, + 0x5580, 0x5581, 0x55c0, 0x55c1, 0x5680, 0x58c0, 0x5700, 0x5702, + 0x5704, 0x5706, 0x5708, 0x570a, 0x570c, 0x570e, 0x5710, 0x5712, + 0x5714, 0x5716, 0x5740, 0x5742, 0x5744, 0x5780, 0x5781, 0x57c0, + 0x57c1, 0x5800, 0x5801, 0x5840, 0x5841, 0x5880, 0x5881, 0x5900, + 0x5901, 0x5902, 0x5903, 0x5940, 0x8ec0, 0x8f00, 0x8fc0, 0x8fc2, + 0x9000, 0x9040, 0x9041, 0x9080, 0x9081, 0x90c0, 0x90c2, 0x9100, + 0x9140, 0x9182, 0x9180, 0x9183, 0x91c1, 0x91c0, 0x91c3, 0x9200, + 0x9201, 0x9240, 0x9280, 0x9282, 0x9284, 0x9281, 0x9285, 0x9287, + 0x9286, 0x9283, 0x92c1, 0x92c0, 0x92c2, +}; + +typedef enum { + UNICODE_GC_Cn, + UNICODE_GC_Lu, + UNICODE_GC_Ll, + UNICODE_GC_Lt, + UNICODE_GC_Lm, + UNICODE_GC_Lo, + UNICODE_GC_Mn, + UNICODE_GC_Mc, + UNICODE_GC_Me, + UNICODE_GC_Nd, + UNICODE_GC_Nl, + UNICODE_GC_No, + UNICODE_GC_Sm, + UNICODE_GC_Sc, + UNICODE_GC_Sk, + UNICODE_GC_So, + UNICODE_GC_Pc, + UNICODE_GC_Pd, + UNICODE_GC_Ps, + UNICODE_GC_Pe, + UNICODE_GC_Pi, + UNICODE_GC_Pf, + UNICODE_GC_Po, + UNICODE_GC_Zs, + UNICODE_GC_Zl, + UNICODE_GC_Zp, + UNICODE_GC_Cc, + UNICODE_GC_Cf, + UNICODE_GC_Cs, + UNICODE_GC_Co, + UNICODE_GC_LC, + UNICODE_GC_L, + UNICODE_GC_M, + UNICODE_GC_N, + UNICODE_GC_S, + UNICODE_GC_P, + UNICODE_GC_Z, + UNICODE_GC_C, + UNICODE_GC_COUNT, +} UnicodeGCEnum; + +static const char unicode_gc_name_table[] = + "Cn,Unassigned" "\0" + "Lu,Uppercase_Letter" "\0" + "Ll,Lowercase_Letter" "\0" + "Lt,Titlecase_Letter" "\0" + "Lm,Modifier_Letter" "\0" + "Lo,Other_Letter" "\0" + "Mn,Nonspacing_Mark" "\0" + "Mc,Spacing_Mark" "\0" + "Me,Enclosing_Mark" "\0" + "Nd,Decimal_Number,digit" "\0" + "Nl,Letter_Number" "\0" + "No,Other_Number" "\0" + "Sm,Math_Symbol" "\0" + "Sc,Currency_Symbol" "\0" + "Sk,Modifier_Symbol" "\0" + "So,Other_Symbol" "\0" + "Pc,Connector_Punctuation" "\0" + "Pd,Dash_Punctuation" "\0" + "Ps,Open_Punctuation" "\0" + "Pe,Close_Punctuation" "\0" + "Pi,Initial_Punctuation" "\0" + "Pf,Final_Punctuation" "\0" + "Po,Other_Punctuation" "\0" + "Zs,Space_Separator" "\0" + "Zl,Line_Separator" "\0" + "Zp,Paragraph_Separator" "\0" + "Cc,Control,cntrl" "\0" + "Cf,Format" "\0" + "Cs,Surrogate" "\0" + "Co,Private_Use" "\0" + "LC,Cased_Letter" "\0" + "L,Letter" "\0" + "M,Mark,Combining_Mark" "\0" + "N,Number" "\0" + "S,Symbol" "\0" + "P,Punctuation,punct" "\0" + "Z,Separator" "\0" + "C,Other" "\0" +; + +static const uint8_t unicode_gc_table[4122] = { + 0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13, + 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, + 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, + 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c, + 0xfa, 0x19, 0x17, 0x16, 0x6d, 0x0f, 0x16, 0x0e, + 0x0f, 0x05, 0x14, 0x0c, 0x1b, 0x0f, 0x0e, 0x0f, + 0x0c, 0x2b, 0x0e, 0x02, 0x36, 0x0e, 0x0b, 0x05, + 0x15, 0x4b, 0x16, 0xe1, 0x0f, 0x0c, 0xc1, 0xe2, + 0x10, 0x0c, 0xe2, 0x00, 0xff, 0x30, 0x02, 0xff, + 0x08, 0x02, 0xff, 0x27, 0xbf, 0x22, 0x21, 0x02, + 0x5f, 0x5f, 0x21, 0x22, 0x61, 0x02, 0x21, 0x02, + 0x41, 0x42, 0x21, 0x02, 0x21, 0x02, 0x9f, 0x7f, + 0x02, 0x5f, 0x5f, 0x21, 0x02, 0x5f, 0x3f, 0x02, + 0x05, 0x3f, 0x22, 0x65, 0x01, 0x03, 0x02, 0x01, + 0x03, 0x02, 0x01, 0x03, 0x02, 0xff, 0x08, 0x02, + 0xff, 0x0a, 0x02, 0x01, 0x03, 0x02, 0x5f, 0x21, + 0x02, 0xff, 0x32, 0xa2, 0x21, 0x02, 0x21, 0x22, + 0x5f, 0x41, 0x02, 0xff, 0x00, 0xe2, 0x3c, 0x25, + 0xe2, 0x12, 0xe4, 0x0a, 0x6e, 0xe4, 0x04, 0xee, + 0x06, 0x84, 0xce, 0x04, 0x0e, 0x04, 0xee, 0x09, + 0xe6, 0x68, 0x7f, 0x04, 0x0e, 0x3f, 0x20, 0x04, + 0x42, 0x16, 0x01, 0x60, 0x2e, 0x01, 0x16, 0x41, + 0x00, 0x01, 0x00, 0x21, 0x02, 0xe1, 0x09, 0x00, + 0xe1, 0x01, 0xe2, 0x1b, 0x3f, 0x02, 0x41, 0x42, + 0xff, 0x10, 0x62, 0x3f, 0x0c, 0x5f, 0x3f, 0x02, + 0xe1, 0x2b, 0xe2, 0x28, 0xff, 0x1a, 0x0f, 0x86, + 0x28, 0xff, 0x2f, 0xff, 0x06, 0x02, 0xff, 0x58, + 0x00, 0xe1, 0x1e, 0x20, 0x04, 0xb6, 0xe2, 0x21, + 0x16, 0x11, 0x20, 0x2f, 0x0d, 0x00, 0xe6, 0x25, + 0x11, 0x06, 0x16, 0x26, 0x16, 0x26, 0x16, 0x06, + 0xe0, 0x00, 0xe5, 0x13, 0x60, 0x65, 0x36, 0xe0, + 0x03, 0xbb, 0x4c, 0x36, 0x0d, 0x36, 0x2f, 0xe6, + 0x03, 0x16, 0x1b, 0x56, 0xe5, 0x18, 0x04, 0xe5, + 0x02, 0xe6, 0x0d, 0xe9, 0x02, 0x76, 0x25, 0x06, + 0xe5, 0x5b, 0x16, 0x05, 0xc6, 0x1b, 0x0f, 0xa6, + 0x24, 0x26, 0x0f, 0x66, 0x25, 0xe9, 0x02, 0x45, + 0x2f, 0x05, 0xf6, 0x06, 0x00, 0x1b, 0x05, 0x06, + 0xe5, 0x16, 0xe6, 0x13, 0x20, 0xe5, 0x51, 0xe6, + 0x03, 0x05, 0xe0, 0x06, 0xe9, 0x02, 0xe5, 0x19, + 0xe6, 0x01, 0x24, 0x0f, 0x56, 0x04, 0x20, 0x06, + 0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01, 0x04, + 0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00, 0xe5, + 0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03, 0x80, + 0xe5, 0x10, 0x0e, 0xc5, 0x3b, 0x80, 0xe6, 0x01, + 0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6, 0x18, + 0x07, 0xe5, 0x2e, 0x06, 0x07, 0x06, 0x05, 0x47, + 0xe6, 0x00, 0x67, 0x06, 0x27, 0x05, 0xc6, 0xe5, + 0x02, 0x26, 0x36, 0xe9, 0x02, 0x16, 0x04, 0xe5, + 0x07, 0x06, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, + 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x05, 0x40, + 0x65, 0x20, 0x06, 0x05, 0x47, 0x66, 0x20, 0x27, + 0x20, 0x27, 0x06, 0x05, 0xe0, 0x00, 0x07, 0x60, + 0x25, 0x00, 0x45, 0x26, 0x20, 0xe9, 0x02, 0x25, + 0x2d, 0xab, 0x0f, 0x0d, 0x05, 0x16, 0x06, 0x20, + 0x26, 0x07, 0x00, 0xa5, 0x60, 0x25, 0x20, 0xe5, + 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x25, 0x00, + 0x25, 0x20, 0x06, 0x00, 0x47, 0x26, 0x60, 0x26, + 0x20, 0x46, 0x40, 0x06, 0xc0, 0x65, 0x00, 0x05, + 0xc0, 0xe9, 0x02, 0x26, 0x45, 0x06, 0x16, 0xe0, + 0x02, 0x26, 0x07, 0x00, 0xe5, 0x01, 0x00, 0x45, + 0x00, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, + 0x85, 0x20, 0x06, 0x05, 0x47, 0x86, 0x00, 0x26, + 0x07, 0x00, 0x27, 0x06, 0x20, 0x05, 0xe0, 0x07, + 0x25, 0x26, 0x20, 0xe9, 0x02, 0x16, 0x0d, 0xc0, + 0x05, 0xa6, 0x00, 0x06, 0x27, 0x00, 0xe5, 0x00, + 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, + 0x25, 0x00, 0x85, 0x20, 0x06, 0x05, 0x07, 0x06, + 0x07, 0x66, 0x20, 0x27, 0x20, 0x27, 0x06, 0xc0, + 0x26, 0x07, 0x60, 0x25, 0x00, 0x45, 0x26, 0x20, + 0xe9, 0x02, 0x0f, 0x05, 0xab, 0xe0, 0x02, 0x06, + 0x05, 0x00, 0xa5, 0x40, 0x45, 0x00, 0x65, 0x40, + 0x25, 0x00, 0x05, 0x00, 0x25, 0x40, 0x25, 0x40, + 0x45, 0x40, 0xe5, 0x04, 0x60, 0x27, 0x06, 0x27, + 0x40, 0x47, 0x00, 0x47, 0x06, 0x20, 0x05, 0xa0, + 0x07, 0xe0, 0x06, 0xe9, 0x02, 0x4b, 0xaf, 0x0d, + 0x0f, 0x80, 0x06, 0x47, 0x06, 0xe5, 0x00, 0x00, + 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x08, 0x20, + 0x06, 0x05, 0x46, 0x67, 0x00, 0x46, 0x00, 0x66, + 0xc0, 0x26, 0x00, 0x45, 0x00, 0x25, 0x20, 0x25, + 0x26, 0x20, 0xe9, 0x02, 0xc0, 0x16, 0xcb, 0x0f, + 0x05, 0x06, 0x27, 0x16, 0xe5, 0x00, 0x00, 0x45, + 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x02, 0x00, 0x85, + 0x20, 0x06, 0x05, 0x07, 0x06, 0x87, 0x00, 0x06, + 0x27, 0x00, 0x27, 0x26, 0xc0, 0x27, 0x80, 0x45, + 0x00, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x00, 0x25, + 0x07, 0xe0, 0x04, 0x26, 0x27, 0xe5, 0x01, 0x00, + 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47, 0x66, + 0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f, 0x60, + 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9, 0x02, + 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27, 0x00, + 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5, 0x01, + 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60, 0x47, + 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0, 0xe9, + 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5, 0x28, + 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04, 0xe6, + 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d, 0x25, + 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10, 0x00, + 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6, 0x01, + 0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xc6, 0x00, + 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05, 0x4f, + 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf, 0xe9, + 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06, 0x0f, + 0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5, 0x00, + 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07, 0x86, + 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6, 0x1c, + 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f, 0x96, + 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27, 0x66, + 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05, 0xe9, + 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46, 0x05, + 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05, 0x06, + 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9, 0x02, + 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01, 0x80, + 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42, 0xe5, + 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05, + 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65, 0x20, + 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05, + 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5, 0x31, + 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46, 0xf6, + 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef, 0x02, + 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11, 0xe5, + 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17, 0xe5, + 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56, 0x4a, + 0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07, 0xe0, + 0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0, 0x01, + 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05, 0x00, + 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c, 0x26, + 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6, 0x03, + 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20, 0xe9, + 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11, 0x76, + 0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x1b, + 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5, 0x1a, + 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02, 0xe5, + 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60, 0x27, + 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36, 0xe9, + 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03, 0xe5, + 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02, 0x0b, + 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27, 0x06, + 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07, 0xc6, + 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00, 0xa7, + 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0, 0xe9, + 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, 0x06, + 0x08, 0xe6, 0x17, 0x20, 0xe6, 0x04, 0xe0, 0x0c, + 0x66, 0x07, 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, + 0x06, 0x87, 0x06, 0x27, 0xe5, 0x00, 0x00, 0x36, + 0xe9, 0x02, 0xd6, 0xef, 0x02, 0xe6, 0x01, 0xef, + 0x01, 0x56, 0x26, 0x07, 0xe5, 0x16, 0x07, 0x66, + 0x27, 0x26, 0x07, 0x46, 0x25, 0xe9, 0x02, 0xe5, + 0x24, 0x06, 0x07, 0x26, 0x47, 0x06, 0x07, 0x46, + 0x27, 0xe0, 0x00, 0x76, 0xe5, 0x1c, 0xe7, 0x00, + 0xe6, 0x00, 0x27, 0x26, 0x40, 0x96, 0xe9, 0x02, + 0x40, 0x45, 0xe9, 0x02, 0xe5, 0x16, 0xa4, 0x36, + 0xe2, 0x01, 0x3f, 0x80, 0xe1, 0x23, 0x20, 0x41, + 0xf6, 0x00, 0xe0, 0x00, 0x46, 0x16, 0xe6, 0x05, + 0x07, 0xc6, 0x65, 0x06, 0xa5, 0x06, 0x25, 0x07, + 0x26, 0x05, 0x80, 0xe2, 0x24, 0xe4, 0x37, 0xe2, + 0x05, 0x04, 0xe2, 0x1a, 0xe4, 0x1d, 0xe6, 0x38, + 0xff, 0x80, 0x0e, 0xe2, 0x00, 0xff, 0x5a, 0xe2, + 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2, + 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe1, 0x00, 0xa2, + 0x20, 0xa1, 0x20, 0xe2, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x3f, 0xc2, 0xe1, 0x00, + 0xe2, 0x06, 0x20, 0xe2, 0x00, 0xe3, 0x00, 0xe2, + 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, 0x82, + 0x00, 0x22, 0x61, 0x03, 0x0e, 0x02, 0x4e, 0x42, + 0x00, 0x22, 0x61, 0x03, 0x4e, 0x62, 0x20, 0x22, + 0x61, 0x00, 0x4e, 0xe2, 0x00, 0x81, 0x4e, 0x20, + 0x42, 0x00, 0x22, 0x61, 0x03, 0x2e, 0x00, 0xf7, + 0x03, 0x9b, 0xb1, 0x36, 0x14, 0x15, 0x12, 0x34, + 0x15, 0x12, 0x14, 0xf6, 0x00, 0x18, 0x19, 0x9b, + 0x17, 0xf6, 0x01, 0x14, 0x15, 0x76, 0x30, 0x56, + 0x0c, 0x12, 0x13, 0xf6, 0x03, 0x0c, 0x16, 0x10, + 0xf6, 0x02, 0x17, 0x9b, 0x00, 0xfb, 0x02, 0x0b, + 0x04, 0x20, 0xab, 0x4c, 0x12, 0x13, 0x04, 0xeb, + 0x02, 0x4c, 0x12, 0x13, 0x00, 0xe4, 0x05, 0x40, + 0xed, 0x1a, 0xe0, 0x06, 0xe6, 0x05, 0x68, 0x06, + 0x48, 0xe6, 0x04, 0xe0, 0x07, 0x2f, 0x01, 0x6f, + 0x01, 0x2f, 0x02, 0x41, 0x22, 0x41, 0x02, 0x0f, + 0x01, 0x2f, 0x0c, 0x81, 0xaf, 0x01, 0x0f, 0x01, + 0x0f, 0x01, 0x0f, 0x61, 0x0f, 0x02, 0x61, 0x02, + 0x65, 0x02, 0x2f, 0x22, 0x21, 0x8c, 0x3f, 0x42, + 0x0f, 0x0c, 0x2f, 0x02, 0x0f, 0xeb, 0x08, 0xea, + 0x1b, 0x3f, 0x6a, 0x0b, 0x2f, 0x60, 0x8c, 0x8f, + 0x2c, 0x6f, 0x0c, 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, + 0x0c, 0xef, 0x17, 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, + 0xef, 0x17, 0xec, 0x80, 0x84, 0xef, 0x00, 0x12, + 0x13, 0x12, 0x13, 0xef, 0x0c, 0x2c, 0xcf, 0x12, + 0x13, 0xef, 0x49, 0x0c, 0xef, 0x16, 0xec, 0x11, + 0xef, 0x20, 0xac, 0xef, 0x40, 0xe0, 0x0e, 0xef, + 0x03, 0xe0, 0x0d, 0xeb, 0x34, 0xef, 0x46, 0xeb, + 0x0e, 0xef, 0x80, 0x2f, 0x0c, 0xef, 0x01, 0x0c, + 0xef, 0x2e, 0xec, 0x00, 0xef, 0x67, 0x0c, 0xef, + 0x80, 0x70, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0xeb, 0x16, 0xef, 0x24, 0x8c, 0x12, 0x13, 0xec, + 0x17, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0xec, 0x08, 0xef, 0x80, 0x78, + 0xec, 0x7b, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0xec, 0x37, 0x12, 0x13, 0x12, 0x13, 0xec, 0x18, + 0x12, 0x13, 0xec, 0x80, 0x7a, 0xef, 0x28, 0xec, + 0x0d, 0x2f, 0xac, 0xef, 0x1f, 0x20, 0xef, 0x80, + 0x02, 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, + 0xdf, 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, + 0x41, 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, + 0x3f, 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, + 0x02, 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, + 0x16, 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, + 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, + 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, + 0xe6, 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, + 0x14, 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, + 0x36, 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0x96, 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, + 0x12, 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, + 0xef, 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, + 0x80, 0x4e, 0xe0, 0x12, 0xef, 0x08, 0x17, 0x56, + 0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, + 0x12, 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11, + 0x84, 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00, + 0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11, + 0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23, + 0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02, + 0xe5, 0x18, 0xef, 0x1e, 0xe0, 0x01, 0x0f, 0xe5, + 0x08, 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, + 0xeb, 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, + 0x02, 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, + 0xe5, 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, + 0x8d, 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, + 0xe0, 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, + 0x84, 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, + 0xe0, 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, + 0xe6, 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, + 0xe5, 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, + 0xee, 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, + 0xff, 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, + 0x04, 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, + 0x61, 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, + 0x5f, 0xff, 0x09, 0xe0, 0x0c, 0x64, 0x3f, 0x05, + 0x24, 0x02, 0xc5, 0x06, 0x45, 0x06, 0x65, 0x06, + 0xe5, 0x0f, 0x27, 0x26, 0x07, 0x6f, 0x06, 0x40, + 0xab, 0x2f, 0x0d, 0x0f, 0xa0, 0xe5, 0x2c, 0x76, + 0xe0, 0x00, 0x27, 0xe5, 0x2a, 0xe7, 0x08, 0x26, + 0xe0, 0x00, 0x36, 0xe9, 0x02, 0xa0, 0xe6, 0x0a, + 0xa5, 0x56, 0x05, 0x16, 0x25, 0x06, 0xe9, 0x02, + 0xe5, 0x14, 0xe6, 0x00, 0x36, 0xe5, 0x0f, 0xe6, + 0x03, 0x27, 0xe0, 0x03, 0x16, 0xe5, 0x15, 0x40, + 0x46, 0x07, 0xe5, 0x27, 0x06, 0x27, 0x66, 0x27, + 0x26, 0x47, 0xf6, 0x05, 0x00, 0x04, 0xe9, 0x02, + 0x60, 0x36, 0x85, 0x06, 0x04, 0xe5, 0x01, 0xe9, + 0x02, 0x85, 0x00, 0xe5, 0x21, 0xa6, 0x27, 0x26, + 0x27, 0x26, 0xe0, 0x01, 0x45, 0x06, 0xe5, 0x00, + 0x06, 0x07, 0x20, 0xe9, 0x02, 0x20, 0x76, 0xe5, + 0x08, 0x04, 0xa5, 0x4f, 0x05, 0x07, 0x06, 0x07, + 0xe5, 0x2a, 0x06, 0x05, 0x46, 0x25, 0x26, 0x85, + 0x26, 0x05, 0x06, 0x05, 0xe0, 0x10, 0x25, 0x04, + 0x36, 0xe5, 0x03, 0x07, 0x26, 0x27, 0x36, 0x05, + 0x24, 0x07, 0x06, 0xe0, 0x02, 0xa5, 0x20, 0xa5, + 0x20, 0xa5, 0xe0, 0x01, 0xc5, 0x00, 0xc5, 0x00, + 0xe2, 0x23, 0x0e, 0x64, 0xe2, 0x01, 0x04, 0x2e, + 0x60, 0xe2, 0x48, 0xe5, 0x1b, 0x27, 0x06, 0x27, + 0x06, 0x27, 0x16, 0x07, 0x06, 0x20, 0xe9, 0x02, + 0xa0, 0xe5, 0xab, 0x1c, 0xe0, 0x04, 0xe5, 0x0f, + 0x60, 0xe5, 0x29, 0x60, 0xfc, 0x87, 0x78, 0xfd, + 0x98, 0x78, 0xe5, 0x80, 0xe6, 0x20, 0xe5, 0x62, + 0xe0, 0x1e, 0xc2, 0xe0, 0x04, 0x82, 0x80, 0x05, + 0x06, 0xe5, 0x02, 0x0c, 0xe5, 0x05, 0x00, 0x85, + 0x00, 0x05, 0x00, 0x25, 0x00, 0x25, 0x00, 0xe5, + 0x64, 0xee, 0x09, 0xef, 0x08, 0xe5, 0x80, 0xe3, + 0x13, 0x12, 0xef, 0x08, 0xe5, 0x38, 0x2f, 0xe5, + 0x2e, 0xef, 0x00, 0xe0, 0x18, 0xe5, 0x04, 0x0d, + 0x4f, 0xe6, 0x08, 0xd6, 0x12, 0x13, 0x16, 0xa0, + 0xe6, 0x08, 0x16, 0x31, 0x30, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x36, 0x12, 0x13, + 0x76, 0x50, 0x56, 0x00, 0x76, 0x11, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x56, 0x0c, 0x11, 0x4c, + 0x00, 0x16, 0x0d, 0x36, 0x60, 0x85, 0x00, 0xe5, + 0x7f, 0x20, 0x1b, 0x00, 0x56, 0x0d, 0x56, 0x12, + 0x13, 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, + 0x36, 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, + 0x0e, 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, + 0x0c, 0x12, 0x13, 0x16, 0x12, 0x13, 0x36, 0xe5, + 0x02, 0x04, 0xe5, 0x25, 0x24, 0xe5, 0x17, 0x40, + 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0x20, 0x45, 0x40, + 0x2d, 0x0c, 0x0e, 0x0f, 0x2d, 0x00, 0x0f, 0x6c, + 0x2f, 0xe0, 0x02, 0x5b, 0x2f, 0x20, 0xe5, 0x04, + 0x00, 0xe5, 0x12, 0x00, 0xe5, 0x0b, 0x00, 0x25, + 0x00, 0xe5, 0x07, 0x20, 0xe5, 0x06, 0xe0, 0x1a, + 0xe5, 0x73, 0x80, 0x56, 0x60, 0xeb, 0x25, 0x40, + 0xef, 0x01, 0xea, 0x2d, 0x6b, 0xef, 0x09, 0x2b, + 0x4f, 0x00, 0xef, 0x05, 0x40, 0x0f, 0xe0, 0x27, + 0xef, 0x25, 0x06, 0xe0, 0x7a, 0xe5, 0x15, 0x40, + 0xe5, 0x29, 0xe0, 0x07, 0x06, 0xeb, 0x13, 0x60, + 0xe5, 0x18, 0x6b, 0xe0, 0x01, 0xe5, 0x0c, 0x0a, + 0xe5, 0x00, 0x0a, 0x80, 0xe5, 0x1e, 0x86, 0x80, + 0xe5, 0x16, 0x00, 0x16, 0xe5, 0x1c, 0x60, 0xe5, + 0x00, 0x16, 0x8a, 0xe0, 0x22, 0xe1, 0x20, 0xe2, + 0x20, 0xe5, 0x46, 0x20, 0xe9, 0x02, 0xa0, 0xe1, + 0x1c, 0x60, 0xe2, 0x1c, 0x60, 0xe5, 0x20, 0xe0, + 0x00, 0xe5, 0x2c, 0xe0, 0x03, 0x16, 0xe1, 0x03, + 0x00, 0xe1, 0x07, 0x00, 0xc1, 0x00, 0x21, 0x00, + 0xe2, 0x03, 0x00, 0xe2, 0x07, 0x00, 0xc2, 0x00, + 0x22, 0x40, 0xe5, 0x2c, 0xe0, 0x04, 0xe5, 0x80, + 0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5, + 0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00, + 0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00, + 0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5, + 0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f, + 0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0, + 0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5, + 0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16, + 0xe5, 0x12, 0xe0, 0x1e, 0xe5, 0x30, 0x60, 0x2b, + 0x25, 0xeb, 0x08, 0x20, 0xeb, 0x26, 0x05, 0x46, + 0x00, 0x26, 0x80, 0x66, 0x65, 0x00, 0x45, 0x00, + 0xe5, 0x15, 0x20, 0x46, 0x60, 0x06, 0xeb, 0x01, + 0xc0, 0xf6, 0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16, + 0xe5, 0x15, 0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f, + 0xe5, 0x14, 0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01, + 0xe5, 0x2e, 0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb, + 0x00, 0xe5, 0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a, + 0xc0, 0x76, 0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5, + 0x41, 0xe0, 0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2, + 0x2b, 0xc0, 0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00, + 0xe9, 0x02, 0xa0, 0xe9, 0x02, 0x65, 0x04, 0x05, + 0xe1, 0x0e, 0x40, 0x86, 0x11, 0x04, 0xe2, 0x0e, + 0xe0, 0x00, 0x2c, 0xe0, 0x80, 0x48, 0xeb, 0x17, + 0x00, 0xe5, 0x22, 0x00, 0x26, 0x11, 0x20, 0x25, + 0xe0, 0x08, 0x45, 0x04, 0x25, 0xe0, 0x00, 0x16, + 0xef, 0x00, 0xe0, 0x19, 0xa6, 0xe5, 0x15, 0xeb, + 0x02, 0x05, 0xe0, 0x00, 0xe5, 0x0e, 0xe6, 0x03, + 0x6b, 0x96, 0xe0, 0x0e, 0xe5, 0x0a, 0x66, 0x76, + 0xe0, 0x1e, 0xe5, 0x0d, 0xcb, 0xe0, 0x0c, 0xe5, + 0x0f, 0xe0, 0x01, 0x07, 0x06, 0x07, 0xe5, 0x2d, + 0xe6, 0x07, 0xd6, 0x60, 0xeb, 0x0c, 0xe9, 0x02, + 0x06, 0x25, 0x26, 0x05, 0xe0, 0x01, 0x46, 0x07, + 0xe5, 0x25, 0x47, 0x66, 0x27, 0x26, 0x36, 0x1b, + 0x76, 0x06, 0xe0, 0x02, 0x1b, 0x20, 0xe5, 0x11, + 0xc0, 0xe9, 0x02, 0xa0, 0x46, 0xe5, 0x1c, 0x86, + 0x07, 0xe6, 0x00, 0x00, 0xe9, 0x02, 0x76, 0x05, + 0x27, 0x05, 0xe0, 0x00, 0xe5, 0x1b, 0x06, 0x36, + 0x05, 0xe0, 0x01, 0x26, 0x07, 0xe5, 0x28, 0x47, + 0xe6, 0x01, 0x27, 0x65, 0x76, 0x66, 0x16, 0x07, + 0x06, 0xe9, 0x02, 0x05, 0x16, 0x05, 0x56, 0x00, + 0xeb, 0x0c, 0xe0, 0x03, 0xe5, 0x0a, 0x00, 0xe5, + 0x11, 0x47, 0x46, 0x27, 0x06, 0x07, 0x26, 0xb6, + 0x06, 0x25, 0x06, 0xe0, 0x36, 0xc5, 0x00, 0x05, + 0x00, 0x65, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x02, + 0x16, 0xa0, 0xe5, 0x27, 0x06, 0x47, 0xe6, 0x00, + 0x80, 0xe9, 0x02, 0xa0, 0x26, 0x27, 0x00, 0xe5, + 0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, + 0x00, 0x25, 0x00, 0x85, 0x00, 0x26, 0x05, 0x27, + 0x06, 0x67, 0x20, 0x27, 0x20, 0x47, 0x20, 0x05, + 0xa0, 0x07, 0x80, 0x85, 0x27, 0x20, 0xc6, 0x40, + 0x86, 0xe0, 0x03, 0xe5, 0x02, 0x00, 0x05, 0x20, + 0x05, 0x00, 0xe5, 0x1e, 0x00, 0x05, 0x47, 0xa6, + 0x00, 0x07, 0x20, 0x07, 0x00, 0x67, 0x00, 0x27, + 0x06, 0x07, 0x06, 0x05, 0x06, 0x05, 0x36, 0x00, + 0x36, 0xe0, 0x00, 0x26, 0xe0, 0x15, 0xe5, 0x2d, + 0x47, 0xe6, 0x00, 0x27, 0x46, 0x07, 0x06, 0x65, + 0x96, 0xe9, 0x02, 0x36, 0x00, 0x16, 0x06, 0x45, + 0xe0, 0x16, 0xe5, 0x28, 0x47, 0xa6, 0x07, 0x06, + 0x67, 0x26, 0x07, 0x26, 0x25, 0x16, 0x05, 0xe0, + 0x00, 0xe9, 0x02, 0xe0, 0x80, 0x1e, 0xe5, 0x27, + 0x47, 0x66, 0x20, 0x67, 0x26, 0x07, 0x26, 0xf6, + 0x0f, 0x65, 0x26, 0xe0, 0x1a, 0xe5, 0x28, 0x47, + 0xe6, 0x00, 0x27, 0x06, 0x07, 0x26, 0x56, 0x05, + 0xe0, 0x03, 0xe9, 0x02, 0xa0, 0xf6, 0x05, 0xe0, + 0x0b, 0xe5, 0x23, 0x06, 0x07, 0x06, 0x27, 0xa6, + 0x07, 0x06, 0x05, 0x16, 0xa0, 0xe9, 0x02, 0xa0, + 0xe9, 0x0c, 0xe0, 0x14, 0xe5, 0x13, 0x20, 0x06, + 0x07, 0x06, 0x27, 0x66, 0x07, 0x86, 0x60, 0xe9, + 0x02, 0x2b, 0x56, 0x0f, 0xc5, 0xe0, 0x80, 0x31, + 0xe5, 0x24, 0x47, 0xe6, 0x01, 0x07, 0x26, 0x16, + 0xe0, 0x5c, 0xe1, 0x18, 0xe2, 0x18, 0xe9, 0x02, + 0xeb, 0x01, 0xe0, 0x04, 0xe5, 0x00, 0x20, 0x05, + 0x20, 0xe5, 0x00, 0x00, 0x25, 0x00, 0xe5, 0x10, + 0xa7, 0x00, 0x27, 0x20, 0x26, 0x07, 0x06, 0x05, + 0x07, 0x05, 0x07, 0x06, 0x56, 0xe0, 0x01, 0xe9, + 0x02, 0xe0, 0x3e, 0xe5, 0x00, 0x20, 0xe5, 0x1f, + 0x47, 0x66, 0x20, 0x26, 0x67, 0x06, 0x05, 0x16, + 0x05, 0x07, 0xe0, 0x13, 0x05, 0xe6, 0x02, 0xe5, + 0x20, 0xa6, 0x07, 0x05, 0x66, 0xf6, 0x00, 0x06, + 0xe0, 0x00, 0x05, 0xa6, 0x27, 0x46, 0xe5, 0x26, + 0xe6, 0x05, 0x07, 0x26, 0x56, 0x05, 0x96, 0xe0, + 0x05, 0xe5, 0x41, 0xc0, 0xf6, 0x02, 0xe0, 0x4e, + 0x06, 0x07, 0x46, 0x07, 0x06, 0x07, 0xe0, 0x50, + 0xe5, 0x19, 0x16, 0xe0, 0x06, 0xe9, 0x02, 0xa0, + 0xe5, 0x01, 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, + 0xa6, 0x07, 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, + 0x02, 0xeb, 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, + 0xe6, 0x0e, 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, + 0x26, 0xe0, 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, + 0x1e, 0xa6, 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, + 0x05, 0x06, 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, + 0x00, 0x25, 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, + 0x00, 0x27, 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, + 0x02, 0xa0, 0xe5, 0x21, 0x04, 0x25, 0x60, 0xe9, + 0x02, 0xe0, 0x80, 0x6e, 0xe5, 0x0b, 0x26, 0x27, + 0x36, 0xc0, 0x26, 0x05, 0x07, 0xe5, 0x05, 0x00, + 0xe5, 0x1a, 0x27, 0x86, 0x40, 0x27, 0x06, 0x07, + 0x06, 0xf6, 0x05, 0xe9, 0x02, 0x06, 0xe0, 0x4d, + 0x05, 0xe0, 0x07, 0xeb, 0x0d, 0xef, 0x00, 0x6d, + 0xef, 0x09, 0xe0, 0x05, 0x16, 0xe5, 0x83, 0x12, + 0xe0, 0x5e, 0xea, 0x67, 0x00, 0x96, 0xe0, 0x03, + 0xe5, 0x80, 0x3c, 0xe0, 0x89, 0xc4, 0xe5, 0x59, + 0x36, 0xe0, 0x05, 0xe5, 0x83, 0xa8, 0xfb, 0x08, + 0x06, 0xa5, 0xe6, 0x07, 0xe0, 0x02, 0xe5, 0x8f, + 0x13, 0x80, 0xe5, 0x81, 0xbf, 0xe0, 0x9a, 0x31, + 0xe5, 0x16, 0xe6, 0x04, 0x47, 0x46, 0xe9, 0x02, + 0xe0, 0x86, 0x3e, 0xe5, 0x81, 0xb1, 0xc0, 0xe5, + 0x17, 0x00, 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47, + 0x00, 0xe9, 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86, + 0x16, 0xe0, 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, + 0x64, 0x16, 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, + 0xcb, 0x00, 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, + 0x81, 0x28, 0x44, 0xe5, 0x20, 0x24, 0x56, 0xe9, + 0x02, 0xe0, 0x80, 0x3e, 0xe1, 0x18, 0xe2, 0x18, + 0xeb, 0x0f, 0x76, 0x80, 0xe1, 0x11, 0x20, 0xe2, + 0x11, 0xe0, 0x24, 0xe5, 0x43, 0x60, 0x06, 0x05, + 0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38, + 0x24, 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0x24, + 0x4a, 0xe0, 0x01, 0xe5, 0x9c, 0x4e, 0xe0, 0x21, + 0xe5, 0x18, 0xe0, 0x59, 0xe5, 0x6b, 0xe0, 0xa1, + 0x75, 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5, + 0x80, 0x9b, 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45, + 0x20, 0x05, 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, + 0x81, 0x04, 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, + 0xe5, 0x05, 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, + 0x20, 0x0f, 0x26, 0x16, 0x7b, 0xe0, 0x8e, 0xd4, + 0xef, 0x80, 0x68, 0xe9, 0x02, 0x4f, 0x40, 0xef, + 0x81, 0x2c, 0xa0, 0xef, 0x0f, 0xe0, 0x07, 0xef, + 0x08, 0x0c, 0xe0, 0x07, 0xe6, 0x26, 0x20, 0xe6, + 0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef, + 0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef, + 0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6, + 0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35, + 0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f, 0xe0, 0x72, + 0xeb, 0x0c, 0xe0, 0x04, 0xeb, 0x0c, 0xe0, 0x04, + 0xef, 0x4f, 0xe0, 0x01, 0xeb, 0x11, 0xe0, 0x7f, + 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xc2, 0x00, + 0xe2, 0x0a, 0xe1, 0x12, 0xe2, 0x12, 0x01, 0x00, + 0x21, 0x20, 0x01, 0x20, 0x21, 0x20, 0x61, 0x00, + 0xe1, 0x00, 0x62, 0x00, 0x02, 0x00, 0xc2, 0x00, + 0xe2, 0x03, 0xe1, 0x12, 0xe2, 0x12, 0x21, 0x00, + 0x61, 0x20, 0xe1, 0x00, 0x00, 0xc1, 0x00, 0xe2, + 0x12, 0x21, 0x00, 0x61, 0x00, 0x81, 0x00, 0x01, + 0x40, 0xc1, 0x00, 0xe2, 0x12, 0xe1, 0x12, 0xe2, + 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, + 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, + 0x12, 0xe1, 0x12, 0xe2, 0x14, 0x20, 0xe1, 0x11, + 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, + 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, + 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, + 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, + 0xa2, 0x3f, 0x20, 0xe9, 0x2a, 0xef, 0x81, 0x78, + 0xe6, 0x2f, 0x6f, 0xe6, 0x2a, 0xef, 0x00, 0x06, + 0xef, 0x06, 0x06, 0x2f, 0x96, 0xe0, 0x07, 0x86, + 0x00, 0xe6, 0x07, 0xe0, 0x83, 0xc8, 0xe2, 0x02, + 0x05, 0xe2, 0x0c, 0xa0, 0xa2, 0xe0, 0x80, 0x4d, + 0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6, 0x00, 0x26, + 0x00, 0x86, 0x80, 0xe4, 0x36, 0xe0, 0x19, 0x06, + 0xe0, 0x68, 0xe5, 0x25, 0x40, 0xc6, 0xc4, 0x20, + 0xe9, 0x02, 0x60, 0x05, 0x0f, 0xe0, 0x80, 0xb8, + 0xe5, 0x16, 0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66, + 0xe9, 0x02, 0x80, 0x0d, 0xe0, 0x81, 0x48, 0xe5, + 0x13, 0x04, 0x66, 0xe9, 0x02, 0xe0, 0x80, 0x4e, + 0xe5, 0x16, 0x26, 0x05, 0xe9, 0x02, 0x60, 0x16, + 0xe0, 0x80, 0x38, 0xe5, 0x17, 0x00, 0x45, 0x06, + 0x25, 0x06, 0xc5, 0x26, 0x85, 0x06, 0xe0, 0x00, + 0x05, 0x04, 0xe0, 0x80, 0x58, 0xc5, 0x00, 0x65, + 0x00, 0x25, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x80, + 0x3d, 0x20, 0xeb, 0x01, 0xc6, 0xe0, 0x21, 0xe1, + 0x1a, 0xe2, 0x1a, 0xc6, 0x04, 0x60, 0xe9, 0x02, + 0x60, 0x36, 0xe0, 0x82, 0x89, 0xeb, 0x33, 0x0f, + 0x4b, 0x0d, 0x6b, 0xe0, 0x44, 0xeb, 0x25, 0x0f, + 0xeb, 0x07, 0xe0, 0x80, 0x3a, 0x65, 0x00, 0xe5, + 0x13, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, + 0xe5, 0x02, 0x00, 0x65, 0x00, 0x05, 0x00, 0x05, + 0xa0, 0x05, 0x60, 0x05, 0x00, 0x05, 0x00, 0x05, + 0x00, 0x45, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, + 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, + 0x00, 0x25, 0x00, 0x05, 0x20, 0x65, 0x00, 0xc5, + 0x00, 0x65, 0x00, 0x65, 0x00, 0x05, 0x00, 0xe5, + 0x02, 0x00, 0xe5, 0x09, 0x80, 0x45, 0x00, 0x85, + 0x00, 0xe5, 0x09, 0xe0, 0x2c, 0x2c, 0xe0, 0x80, + 0x86, 0xef, 0x24, 0x60, 0xef, 0x5c, 0xe0, 0x04, + 0xef, 0x07, 0x20, 0xef, 0x07, 0x00, 0xef, 0x07, + 0x00, 0xef, 0x1d, 0xe0, 0x02, 0xeb, 0x05, 0xef, + 0x80, 0x19, 0xe0, 0x30, 0xef, 0x15, 0xe0, 0x05, + 0xef, 0x24, 0x60, 0xef, 0x01, 0xc0, 0x2f, 0xe0, + 0x06, 0xaf, 0xe0, 0x80, 0x12, 0xef, 0x80, 0x73, + 0x8e, 0xef, 0x82, 0x51, 0x40, 0xef, 0x09, 0x40, + 0xef, 0x05, 0x40, 0xef, 0x80, 0x52, 0xa0, 0xef, + 0x04, 0x60, 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, + 0xef, 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, + 0x20, 0xe0, 0x00, 0xef, 0x16, 0x20, 0xef, 0x04, + 0x60, 0x2f, 0xe0, 0x06, 0xec, 0x01, 0xe0, 0x1f, + 0xef, 0x80, 0xd0, 0xe0, 0x00, 0xef, 0x06, 0x20, + 0xef, 0x05, 0x40, 0xef, 0x03, 0x40, 0xef, 0x31, + 0x00, 0x0f, 0x60, 0xef, 0x08, 0x20, 0xef, 0x04, + 0x60, 0xef, 0x02, 0xc0, 0xef, 0x80, 0x0b, 0x00, + 0xef, 0x54, 0xe9, 0x02, 0x0f, 0xe0, 0x83, 0x7d, + 0xe5, 0xc0, 0x66, 0x58, 0xe0, 0x18, 0xe5, 0x90, + 0x96, 0x20, 0xe5, 0x96, 0x06, 0x20, 0xe5, 0x9c, + 0xa9, 0xe0, 0x07, 0xe5, 0x81, 0xe6, 0xe0, 0x89, + 0x1a, 0xe5, 0x81, 0x96, 0xe0, 0x85, 0x5a, 0xe5, + 0x92, 0xc3, 0x80, 0xe5, 0xa0, 0xa2, 0xe0, 0xca, + 0x8a, 0xff, 0x1b, 0xe0, 0x16, 0xfb, 0x58, 0xe0, + 0x78, 0xe6, 0x80, 0x68, 0xe0, 0xc0, 0xbd, 0x88, + 0xfd, 0xc0, 0xbf, 0x76, 0x20, 0xfd, 0xc0, 0xbf, + 0x76, 0x20, +}; + +typedef enum { + UNICODE_SCRIPT_Unknown, + UNICODE_SCRIPT_Adlam, + UNICODE_SCRIPT_Ahom, + UNICODE_SCRIPT_Anatolian_Hieroglyphs, + UNICODE_SCRIPT_Arabic, + UNICODE_SCRIPT_Armenian, + UNICODE_SCRIPT_Avestan, + UNICODE_SCRIPT_Balinese, + UNICODE_SCRIPT_Bamum, + UNICODE_SCRIPT_Bassa_Vah, + UNICODE_SCRIPT_Batak, + UNICODE_SCRIPT_Bengali, + UNICODE_SCRIPT_Beria_Erfe, + UNICODE_SCRIPT_Bhaiksuki, + UNICODE_SCRIPT_Bopomofo, + UNICODE_SCRIPT_Brahmi, + UNICODE_SCRIPT_Braille, + UNICODE_SCRIPT_Buginese, + UNICODE_SCRIPT_Buhid, + UNICODE_SCRIPT_Canadian_Aboriginal, + UNICODE_SCRIPT_Carian, + UNICODE_SCRIPT_Caucasian_Albanian, + UNICODE_SCRIPT_Chakma, + UNICODE_SCRIPT_Cham, + UNICODE_SCRIPT_Cherokee, + UNICODE_SCRIPT_Chorasmian, + UNICODE_SCRIPT_Common, + UNICODE_SCRIPT_Coptic, + UNICODE_SCRIPT_Cuneiform, + UNICODE_SCRIPT_Cypriot, + UNICODE_SCRIPT_Cyrillic, + UNICODE_SCRIPT_Cypro_Minoan, + UNICODE_SCRIPT_Deseret, + UNICODE_SCRIPT_Devanagari, + UNICODE_SCRIPT_Dives_Akuru, + UNICODE_SCRIPT_Dogra, + UNICODE_SCRIPT_Duployan, + UNICODE_SCRIPT_Egyptian_Hieroglyphs, + UNICODE_SCRIPT_Elbasan, + UNICODE_SCRIPT_Elymaic, + UNICODE_SCRIPT_Ethiopic, + UNICODE_SCRIPT_Georgian, + UNICODE_SCRIPT_Glagolitic, + UNICODE_SCRIPT_Gothic, + UNICODE_SCRIPT_Garay, + UNICODE_SCRIPT_Grantha, + UNICODE_SCRIPT_Greek, + UNICODE_SCRIPT_Gujarati, + UNICODE_SCRIPT_Gunjala_Gondi, + UNICODE_SCRIPT_Gurmukhi, + UNICODE_SCRIPT_Gurung_Khema, + UNICODE_SCRIPT_Han, + UNICODE_SCRIPT_Hangul, + UNICODE_SCRIPT_Hanifi_Rohingya, + UNICODE_SCRIPT_Hanunoo, + UNICODE_SCRIPT_Hatran, + UNICODE_SCRIPT_Hebrew, + UNICODE_SCRIPT_Hiragana, + UNICODE_SCRIPT_Imperial_Aramaic, + UNICODE_SCRIPT_Inherited, + UNICODE_SCRIPT_Inscriptional_Pahlavi, + UNICODE_SCRIPT_Inscriptional_Parthian, + UNICODE_SCRIPT_Javanese, + UNICODE_SCRIPT_Kaithi, + UNICODE_SCRIPT_Kannada, + UNICODE_SCRIPT_Katakana, + UNICODE_SCRIPT_Katakana_Or_Hiragana, + UNICODE_SCRIPT_Kawi, + UNICODE_SCRIPT_Kayah_Li, + UNICODE_SCRIPT_Kharoshthi, + UNICODE_SCRIPT_Khmer, + UNICODE_SCRIPT_Khojki, + UNICODE_SCRIPT_Khitan_Small_Script, + UNICODE_SCRIPT_Khudawadi, + UNICODE_SCRIPT_Kirat_Rai, + UNICODE_SCRIPT_Lao, + UNICODE_SCRIPT_Latin, + UNICODE_SCRIPT_Lepcha, + UNICODE_SCRIPT_Limbu, + UNICODE_SCRIPT_Linear_A, + UNICODE_SCRIPT_Linear_B, + UNICODE_SCRIPT_Lisu, + UNICODE_SCRIPT_Lycian, + UNICODE_SCRIPT_Lydian, + UNICODE_SCRIPT_Makasar, + UNICODE_SCRIPT_Mahajani, + UNICODE_SCRIPT_Malayalam, + UNICODE_SCRIPT_Mandaic, + UNICODE_SCRIPT_Manichaean, + UNICODE_SCRIPT_Marchen, + UNICODE_SCRIPT_Masaram_Gondi, + UNICODE_SCRIPT_Medefaidrin, + UNICODE_SCRIPT_Meetei_Mayek, + UNICODE_SCRIPT_Mende_Kikakui, + UNICODE_SCRIPT_Meroitic_Cursive, + UNICODE_SCRIPT_Meroitic_Hieroglyphs, + UNICODE_SCRIPT_Miao, + UNICODE_SCRIPT_Modi, + UNICODE_SCRIPT_Mongolian, + UNICODE_SCRIPT_Mro, + UNICODE_SCRIPT_Multani, + UNICODE_SCRIPT_Myanmar, + UNICODE_SCRIPT_Nabataean, + UNICODE_SCRIPT_Nag_Mundari, + UNICODE_SCRIPT_Nandinagari, + UNICODE_SCRIPT_New_Tai_Lue, + UNICODE_SCRIPT_Newa, + UNICODE_SCRIPT_Nko, + UNICODE_SCRIPT_Nushu, + UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong, + UNICODE_SCRIPT_Ogham, + UNICODE_SCRIPT_Ol_Chiki, + UNICODE_SCRIPT_Ol_Onal, + UNICODE_SCRIPT_Old_Hungarian, + UNICODE_SCRIPT_Old_Italic, + UNICODE_SCRIPT_Old_North_Arabian, + UNICODE_SCRIPT_Old_Permic, + UNICODE_SCRIPT_Old_Persian, + UNICODE_SCRIPT_Old_Sogdian, + UNICODE_SCRIPT_Old_South_Arabian, + UNICODE_SCRIPT_Old_Turkic, + UNICODE_SCRIPT_Old_Uyghur, + UNICODE_SCRIPT_Oriya, + UNICODE_SCRIPT_Osage, + UNICODE_SCRIPT_Osmanya, + UNICODE_SCRIPT_Pahawh_Hmong, + UNICODE_SCRIPT_Palmyrene, + UNICODE_SCRIPT_Pau_Cin_Hau, + UNICODE_SCRIPT_Phags_Pa, + UNICODE_SCRIPT_Phoenician, + UNICODE_SCRIPT_Psalter_Pahlavi, + UNICODE_SCRIPT_Rejang, + UNICODE_SCRIPT_Runic, + UNICODE_SCRIPT_Samaritan, + UNICODE_SCRIPT_Saurashtra, + UNICODE_SCRIPT_Sharada, + UNICODE_SCRIPT_Shavian, + UNICODE_SCRIPT_Siddham, + UNICODE_SCRIPT_Sidetic, + UNICODE_SCRIPT_SignWriting, + UNICODE_SCRIPT_Sinhala, + UNICODE_SCRIPT_Sogdian, + UNICODE_SCRIPT_Sora_Sompeng, + UNICODE_SCRIPT_Soyombo, + UNICODE_SCRIPT_Sundanese, + UNICODE_SCRIPT_Sunuwar, + UNICODE_SCRIPT_Syloti_Nagri, + UNICODE_SCRIPT_Syriac, + UNICODE_SCRIPT_Tagalog, + UNICODE_SCRIPT_Tagbanwa, + UNICODE_SCRIPT_Tai_Le, + UNICODE_SCRIPT_Tai_Tham, + UNICODE_SCRIPT_Tai_Viet, + UNICODE_SCRIPT_Tai_Yo, + UNICODE_SCRIPT_Takri, + UNICODE_SCRIPT_Tamil, + UNICODE_SCRIPT_Tangut, + UNICODE_SCRIPT_Telugu, + UNICODE_SCRIPT_Thaana, + UNICODE_SCRIPT_Thai, + UNICODE_SCRIPT_Tibetan, + UNICODE_SCRIPT_Tifinagh, + UNICODE_SCRIPT_Tirhuta, + UNICODE_SCRIPT_Tangsa, + UNICODE_SCRIPT_Todhri, + UNICODE_SCRIPT_Tolong_Siki, + UNICODE_SCRIPT_Toto, + UNICODE_SCRIPT_Tulu_Tigalari, + UNICODE_SCRIPT_Ugaritic, + UNICODE_SCRIPT_Vai, + UNICODE_SCRIPT_Vithkuqi, + UNICODE_SCRIPT_Wancho, + UNICODE_SCRIPT_Warang_Citi, + UNICODE_SCRIPT_Yezidi, + UNICODE_SCRIPT_Yi, + UNICODE_SCRIPT_Zanabazar_Square, + UNICODE_SCRIPT_COUNT, +} UnicodeScriptEnum; + +static const char unicode_script_name_table[] = + "Adlam,Adlm" "\0" + "Ahom,Ahom" "\0" + "Anatolian_Hieroglyphs,Hluw" "\0" + "Arabic,Arab" "\0" + "Armenian,Armn" "\0" + "Avestan,Avst" "\0" + "Balinese,Bali" "\0" + "Bamum,Bamu" "\0" + "Bassa_Vah,Bass" "\0" + "Batak,Batk" "\0" + "Bengali,Beng" "\0" + "Beria_Erfe,Berf" "\0" + "Bhaiksuki,Bhks" "\0" + "Bopomofo,Bopo" "\0" + "Brahmi,Brah" "\0" + "Braille,Brai" "\0" + "Buginese,Bugi" "\0" + "Buhid,Buhd" "\0" + "Canadian_Aboriginal,Cans" "\0" + "Carian,Cari" "\0" + "Caucasian_Albanian,Aghb" "\0" + "Chakma,Cakm" "\0" + "Cham,Cham" "\0" + "Cherokee,Cher" "\0" + "Chorasmian,Chrs" "\0" + "Common,Zyyy" "\0" + "Coptic,Copt,Qaac" "\0" + "Cuneiform,Xsux" "\0" + "Cypriot,Cprt" "\0" + "Cyrillic,Cyrl" "\0" + "Cypro_Minoan,Cpmn" "\0" + "Deseret,Dsrt" "\0" + "Devanagari,Deva" "\0" + "Dives_Akuru,Diak" "\0" + "Dogra,Dogr" "\0" + "Duployan,Dupl" "\0" + "Egyptian_Hieroglyphs,Egyp" "\0" + "Elbasan,Elba" "\0" + "Elymaic,Elym" "\0" + "Ethiopic,Ethi" "\0" + "Georgian,Geor" "\0" + "Glagolitic,Glag" "\0" + "Gothic,Goth" "\0" + "Garay,Gara" "\0" + "Grantha,Gran" "\0" + "Greek,Grek" "\0" + "Gujarati,Gujr" "\0" + "Gunjala_Gondi,Gong" "\0" + "Gurmukhi,Guru" "\0" + "Gurung_Khema,Gukh" "\0" + "Han,Hani" "\0" + "Hangul,Hang" "\0" + "Hanifi_Rohingya,Rohg" "\0" + "Hanunoo,Hano" "\0" + "Hatran,Hatr" "\0" + "Hebrew,Hebr" "\0" + "Hiragana,Hira" "\0" + "Imperial_Aramaic,Armi" "\0" + "Inherited,Zinh,Qaai" "\0" + "Inscriptional_Pahlavi,Phli" "\0" + "Inscriptional_Parthian,Prti" "\0" + "Javanese,Java" "\0" + "Kaithi,Kthi" "\0" + "Kannada,Knda" "\0" + "Katakana,Kana" "\0" + "Katakana_Or_Hiragana,Hrkt" "\0" + "Kawi,Kawi" "\0" + "Kayah_Li,Kali" "\0" + "Kharoshthi,Khar" "\0" + "Khmer,Khmr" "\0" + "Khojki,Khoj" "\0" + "Khitan_Small_Script,Kits" "\0" + "Khudawadi,Sind" "\0" + "Kirat_Rai,Krai" "\0" + "Lao,Laoo" "\0" + "Latin,Latn" "\0" + "Lepcha,Lepc" "\0" + "Limbu,Limb" "\0" + "Linear_A,Lina" "\0" + "Linear_B,Linb" "\0" + "Lisu,Lisu" "\0" + "Lycian,Lyci" "\0" + "Lydian,Lydi" "\0" + "Makasar,Maka" "\0" + "Mahajani,Mahj" "\0" + "Malayalam,Mlym" "\0" + "Mandaic,Mand" "\0" + "Manichaean,Mani" "\0" + "Marchen,Marc" "\0" + "Masaram_Gondi,Gonm" "\0" + "Medefaidrin,Medf" "\0" + "Meetei_Mayek,Mtei" "\0" + "Mende_Kikakui,Mend" "\0" + "Meroitic_Cursive,Merc" "\0" + "Meroitic_Hieroglyphs,Mero" "\0" + "Miao,Plrd" "\0" + "Modi,Modi" "\0" + "Mongolian,Mong" "\0" + "Mro,Mroo" "\0" + "Multani,Mult" "\0" + "Myanmar,Mymr" "\0" + "Nabataean,Nbat" "\0" + "Nag_Mundari,Nagm" "\0" + "Nandinagari,Nand" "\0" + "New_Tai_Lue,Talu" "\0" + "Newa,Newa" "\0" + "Nko,Nkoo" "\0" + "Nushu,Nshu" "\0" + "Nyiakeng_Puachue_Hmong,Hmnp" "\0" + "Ogham,Ogam" "\0" + "Ol_Chiki,Olck" "\0" + "Ol_Onal,Onao" "\0" + "Old_Hungarian,Hung" "\0" + "Old_Italic,Ital" "\0" + "Old_North_Arabian,Narb" "\0" + "Old_Permic,Perm" "\0" + "Old_Persian,Xpeo" "\0" + "Old_Sogdian,Sogo" "\0" + "Old_South_Arabian,Sarb" "\0" + "Old_Turkic,Orkh" "\0" + "Old_Uyghur,Ougr" "\0" + "Oriya,Orya" "\0" + "Osage,Osge" "\0" + "Osmanya,Osma" "\0" + "Pahawh_Hmong,Hmng" "\0" + "Palmyrene,Palm" "\0" + "Pau_Cin_Hau,Pauc" "\0" + "Phags_Pa,Phag" "\0" + "Phoenician,Phnx" "\0" + "Psalter_Pahlavi,Phlp" "\0" + "Rejang,Rjng" "\0" + "Runic,Runr" "\0" + "Samaritan,Samr" "\0" + "Saurashtra,Saur" "\0" + "Sharada,Shrd" "\0" + "Shavian,Shaw" "\0" + "Siddham,Sidd" "\0" + "Sidetic,Sidt" "\0" + "SignWriting,Sgnw" "\0" + "Sinhala,Sinh" "\0" + "Sogdian,Sogd" "\0" + "Sora_Sompeng,Sora" "\0" + "Soyombo,Soyo" "\0" + "Sundanese,Sund" "\0" + "Sunuwar,Sunu" "\0" + "Syloti_Nagri,Sylo" "\0" + "Syriac,Syrc" "\0" + "Tagalog,Tglg" "\0" + "Tagbanwa,Tagb" "\0" + "Tai_Le,Tale" "\0" + "Tai_Tham,Lana" "\0" + "Tai_Viet,Tavt" "\0" + "Tai_Yo,Tayo" "\0" + "Takri,Takr" "\0" + "Tamil,Taml" "\0" + "Tangut,Tang" "\0" + "Telugu,Telu" "\0" + "Thaana,Thaa" "\0" + "Thai,Thai" "\0" + "Tibetan,Tibt" "\0" + "Tifinagh,Tfng" "\0" + "Tirhuta,Tirh" "\0" + "Tangsa,Tnsa" "\0" + "Todhri,Todr" "\0" + "Tolong_Siki,Tols" "\0" + "Toto,Toto" "\0" + "Tulu_Tigalari,Tutg" "\0" + "Ugaritic,Ugar" "\0" + "Vai,Vaii" "\0" + "Vithkuqi,Vith" "\0" + "Wancho,Wcho" "\0" + "Warang_Citi,Wara" "\0" + "Yezidi,Yezi" "\0" + "Yi,Yiii" "\0" + "Zanabazar_Square,Zanb" "\0" +; + +static const uint8_t unicode_script_table[2818] = { + 0xc0, 0x1a, 0x99, 0x4c, 0x85, 0x1a, 0x99, 0x4c, + 0xae, 0x1a, 0x80, 0x4c, 0x8e, 0x1a, 0x80, 0x4c, + 0x84, 0x1a, 0x96, 0x4c, 0x80, 0x1a, 0x9e, 0x4c, + 0x80, 0x1a, 0xe1, 0x60, 0x4c, 0xa6, 0x1a, 0x84, + 0x4c, 0x84, 0x1a, 0x81, 0x0e, 0x93, 0x1a, 0xe0, + 0x0f, 0x3b, 0x83, 0x2e, 0x80, 0x1a, 0x82, 0x2e, + 0x01, 0x83, 0x2e, 0x80, 0x1a, 0x80, 0x2e, 0x03, + 0x80, 0x2e, 0x80, 0x1a, 0x80, 0x2e, 0x80, 0x1a, + 0x82, 0x2e, 0x00, 0x80, 0x2e, 0x00, 0x93, 0x2e, + 0x00, 0xbe, 0x2e, 0x8d, 0x1b, 0x8f, 0x2e, 0xe0, + 0x24, 0x1e, 0x81, 0x3b, 0xe0, 0x48, 0x1e, 0x00, + 0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05, + 0x00, 0xb6, 0x38, 0x07, 0x9a, 0x38, 0x03, 0x85, + 0x38, 0x0a, 0x84, 0x04, 0x80, 0x1a, 0x85, 0x04, + 0x80, 0x1a, 0x8d, 0x04, 0x80, 0x1a, 0x82, 0x04, + 0x80, 0x1a, 0x9f, 0x04, 0x80, 0x1a, 0x89, 0x04, + 0x8a, 0x3b, 0x99, 0x04, 0x80, 0x3b, 0xe0, 0x0b, + 0x04, 0x80, 0x1a, 0xa1, 0x04, 0x8d, 0x93, 0x00, + 0xbb, 0x93, 0x01, 0x82, 0x93, 0xaf, 0x04, 0xb1, + 0x9e, 0x0d, 0xba, 0x6b, 0x01, 0x82, 0x6b, 0xad, + 0x85, 0x01, 0x8e, 0x85, 0x00, 0x9b, 0x57, 0x01, + 0x80, 0x57, 0x00, 0x8a, 0x93, 0x04, 0xa1, 0x04, + 0x04, 0xca, 0x04, 0x80, 0x1a, 0x9c, 0x04, 0xd0, + 0x21, 0x83, 0x3b, 0x8e, 0x21, 0x81, 0x1a, 0x99, + 0x21, 0x83, 0x0b, 0x00, 0x87, 0x0b, 0x01, 0x81, + 0x0b, 0x01, 0x95, 0x0b, 0x00, 0x86, 0x0b, 0x00, + 0x80, 0x0b, 0x02, 0x83, 0x0b, 0x01, 0x88, 0x0b, + 0x01, 0x81, 0x0b, 0x01, 0x83, 0x0b, 0x07, 0x80, + 0x0b, 0x03, 0x81, 0x0b, 0x00, 0x84, 0x0b, 0x01, + 0x98, 0x0b, 0x01, 0x82, 0x31, 0x00, 0x85, 0x31, + 0x03, 0x81, 0x31, 0x01, 0x95, 0x31, 0x00, 0x86, + 0x31, 0x00, 0x81, 0x31, 0x00, 0x81, 0x31, 0x00, + 0x81, 0x31, 0x01, 0x80, 0x31, 0x00, 0x84, 0x31, + 0x03, 0x81, 0x31, 0x01, 0x82, 0x31, 0x02, 0x80, + 0x31, 0x06, 0x83, 0x31, 0x00, 0x80, 0x31, 0x06, + 0x90, 0x31, 0x09, 0x82, 0x2f, 0x00, 0x88, 0x2f, + 0x00, 0x82, 0x2f, 0x00, 0x95, 0x2f, 0x00, 0x86, + 0x2f, 0x00, 0x81, 0x2f, 0x00, 0x84, 0x2f, 0x01, + 0x89, 0x2f, 0x00, 0x82, 0x2f, 0x00, 0x82, 0x2f, + 0x01, 0x80, 0x2f, 0x0e, 0x83, 0x2f, 0x01, 0x8b, + 0x2f, 0x06, 0x86, 0x2f, 0x00, 0x82, 0x7a, 0x00, + 0x87, 0x7a, 0x01, 0x81, 0x7a, 0x01, 0x95, 0x7a, + 0x00, 0x86, 0x7a, 0x00, 0x81, 0x7a, 0x00, 0x84, + 0x7a, 0x01, 0x88, 0x7a, 0x01, 0x81, 0x7a, 0x01, + 0x82, 0x7a, 0x06, 0x82, 0x7a, 0x03, 0x81, 0x7a, + 0x00, 0x84, 0x7a, 0x01, 0x91, 0x7a, 0x09, 0x81, + 0x9b, 0x00, 0x85, 0x9b, 0x02, 0x82, 0x9b, 0x00, + 0x83, 0x9b, 0x02, 0x81, 0x9b, 0x00, 0x80, 0x9b, + 0x00, 0x81, 0x9b, 0x02, 0x81, 0x9b, 0x02, 0x82, + 0x9b, 0x02, 0x8b, 0x9b, 0x03, 0x84, 0x9b, 0x02, + 0x82, 0x9b, 0x00, 0x83, 0x9b, 0x01, 0x80, 0x9b, + 0x05, 0x80, 0x9b, 0x0d, 0x94, 0x9b, 0x04, 0x8c, + 0x9d, 0x00, 0x82, 0x9d, 0x00, 0x96, 0x9d, 0x00, + 0x8f, 0x9d, 0x01, 0x88, 0x9d, 0x00, 0x82, 0x9d, + 0x00, 0x83, 0x9d, 0x06, 0x81, 0x9d, 0x00, 0x82, + 0x9d, 0x00, 0x81, 0x9d, 0x01, 0x83, 0x9d, 0x01, + 0x89, 0x9d, 0x06, 0x88, 0x9d, 0x8c, 0x40, 0x00, + 0x82, 0x40, 0x00, 0x96, 0x40, 0x00, 0x89, 0x40, + 0x00, 0x84, 0x40, 0x01, 0x88, 0x40, 0x00, 0x82, + 0x40, 0x00, 0x83, 0x40, 0x06, 0x81, 0x40, 0x04, + 0x82, 0x40, 0x00, 0x83, 0x40, 0x01, 0x89, 0x40, + 0x00, 0x82, 0x40, 0x0b, 0x8c, 0x56, 0x00, 0x82, + 0x56, 0x00, 0xb2, 0x56, 0x00, 0x82, 0x56, 0x00, + 0x85, 0x56, 0x03, 0x8f, 0x56, 0x01, 0x99, 0x56, + 0x00, 0x82, 0x8c, 0x00, 0x91, 0x8c, 0x02, 0x97, + 0x8c, 0x00, 0x88, 0x8c, 0x00, 0x80, 0x8c, 0x01, + 0x86, 0x8c, 0x02, 0x80, 0x8c, 0x03, 0x85, 0x8c, + 0x00, 0x80, 0x8c, 0x00, 0x87, 0x8c, 0x05, 0x89, + 0x8c, 0x01, 0x82, 0x8c, 0x0b, 0xb9, 0x9f, 0x03, + 0x80, 0x1a, 0x9b, 0x9f, 0x24, 0x81, 0x4b, 0x00, + 0x80, 0x4b, 0x00, 0x84, 0x4b, 0x00, 0x97, 0x4b, + 0x00, 0x80, 0x4b, 0x00, 0x96, 0x4b, 0x01, 0x84, + 0x4b, 0x00, 0x80, 0x4b, 0x00, 0x86, 0x4b, 0x00, + 0x89, 0x4b, 0x01, 0x83, 0x4b, 0x1f, 0xc7, 0xa0, + 0x00, 0xa3, 0xa0, 0x03, 0xa6, 0xa0, 0x00, 0xa3, + 0xa0, 0x00, 0x8e, 0xa0, 0x00, 0x86, 0xa0, 0x83, + 0x1a, 0x81, 0xa0, 0x24, 0xe0, 0x3f, 0x65, 0xa5, + 0x29, 0x00, 0x80, 0x29, 0x04, 0x80, 0x29, 0x01, + 0xaa, 0x29, 0x80, 0x1a, 0x83, 0x29, 0xe0, 0x9f, + 0x34, 0xc8, 0x28, 0x00, 0x83, 0x28, 0x01, 0x86, + 0x28, 0x00, 0x80, 0x28, 0x00, 0x83, 0x28, 0x01, + 0xa8, 0x28, 0x00, 0x83, 0x28, 0x01, 0xa0, 0x28, + 0x00, 0x83, 0x28, 0x01, 0x86, 0x28, 0x00, 0x80, + 0x28, 0x00, 0x83, 0x28, 0x01, 0x8e, 0x28, 0x00, + 0xb8, 0x28, 0x00, 0x83, 0x28, 0x01, 0xc2, 0x28, + 0x01, 0x9f, 0x28, 0x02, 0x99, 0x28, 0x05, 0xd5, + 0x18, 0x01, 0x85, 0x18, 0x01, 0xe2, 0x1f, 0x13, + 0x9c, 0x6e, 0x02, 0xca, 0x84, 0x82, 0x1a, 0x8a, + 0x84, 0x06, 0x95, 0x94, 0x08, 0x80, 0x94, 0x94, + 0x36, 0x81, 0x1a, 0x08, 0x93, 0x12, 0x0b, 0x8c, + 0x95, 0x00, 0x82, 0x95, 0x00, 0x81, 0x95, 0x0b, + 0xdd, 0x46, 0x01, 0x89, 0x46, 0x05, 0x89, 0x46, + 0x05, 0x81, 0x62, 0x81, 0x1a, 0x80, 0x62, 0x80, + 0x1a, 0x93, 0x62, 0x05, 0xd8, 0x62, 0x06, 0xaa, + 0x62, 0x04, 0xc5, 0x13, 0x09, 0x9e, 0x4e, 0x00, + 0x8b, 0x4e, 0x03, 0x8b, 0x4e, 0x03, 0x80, 0x4e, + 0x02, 0x8b, 0x4e, 0x9d, 0x96, 0x01, 0x84, 0x96, + 0x0a, 0xab, 0x69, 0x03, 0x99, 0x69, 0x05, 0x8a, + 0x69, 0x02, 0x81, 0x69, 0x9f, 0x46, 0x9b, 0x11, + 0x01, 0x81, 0x11, 0xbe, 0x97, 0x00, 0x9c, 0x97, + 0x01, 0x8a, 0x97, 0x05, 0x89, 0x97, 0x05, 0x8d, + 0x97, 0x01, 0xad, 0x3b, 0x01, 0x8b, 0x3b, 0x13, + 0xcc, 0x07, 0x00, 0xb1, 0x07, 0xbf, 0x90, 0xb3, + 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x4d, 0x02, 0x8e, + 0x4d, 0x02, 0x82, 0x4d, 0xaf, 0x6f, 0x8a, 0x1e, + 0x04, 0xaa, 0x29, 0x01, 0x82, 0x29, 0x87, 0x90, + 0x07, 0x82, 0x3b, 0x80, 0x1a, 0x8c, 0x3b, 0x80, + 0x1a, 0x86, 0x3b, 0x83, 0x1a, 0x80, 0x3b, 0x85, + 0x1a, 0x80, 0x3b, 0x82, 0x1a, 0x81, 0x3b, 0x80, + 0x1a, 0x04, 0xa5, 0x4c, 0x84, 0x2e, 0x80, 0x1e, + 0xb0, 0x4c, 0x84, 0x2e, 0x83, 0x4c, 0x84, 0x2e, + 0x8c, 0x4c, 0x80, 0x1e, 0xc5, 0x4c, 0x80, 0x2e, + 0xbf, 0x3b, 0xe0, 0x9f, 0x4c, 0x95, 0x2e, 0x01, + 0x85, 0x2e, 0x01, 0xa5, 0x2e, 0x01, 0x85, 0x2e, + 0x01, 0x87, 0x2e, 0x00, 0x80, 0x2e, 0x00, 0x80, + 0x2e, 0x00, 0x80, 0x2e, 0x00, 0x9e, 0x2e, 0x01, + 0xb4, 0x2e, 0x00, 0x8e, 0x2e, 0x00, 0x8d, 0x2e, + 0x01, 0x85, 0x2e, 0x00, 0x92, 0x2e, 0x01, 0x82, + 0x2e, 0x00, 0x88, 0x2e, 0x00, 0x8b, 0x1a, 0x81, + 0x3b, 0xd6, 0x1a, 0x00, 0x8a, 0x1a, 0x80, 0x4c, + 0x01, 0x8a, 0x1a, 0x80, 0x4c, 0x8e, 0x1a, 0x00, + 0x8c, 0x4c, 0x02, 0xa1, 0x1a, 0x0d, 0xa0, 0x3b, + 0x0e, 0xa5, 0x1a, 0x80, 0x2e, 0x82, 0x1a, 0x81, + 0x4c, 0x85, 0x1a, 0x80, 0x4c, 0x9a, 0x1a, 0x80, + 0x4c, 0x90, 0x1a, 0xa8, 0x4c, 0x82, 0x1a, 0x03, + 0xe2, 0x39, 0x1a, 0x15, 0x8a, 0x1a, 0x14, 0xe3, + 0x3f, 0x1a, 0xe0, 0x9f, 0x10, 0xe2, 0x13, 0x1a, + 0x01, 0xe0, 0x29, 0x1a, 0xdf, 0x2a, 0x9f, 0x4c, + 0xe0, 0x13, 0x1b, 0x04, 0x86, 0x1b, 0xa5, 0x29, + 0x00, 0x80, 0x29, 0x04, 0x80, 0x29, 0x01, 0xb7, + 0xa1, 0x06, 0x81, 0xa1, 0x0d, 0x80, 0xa1, 0x96, + 0x28, 0x08, 0x86, 0x28, 0x00, 0x86, 0x28, 0x00, + 0x86, 0x28, 0x00, 0x86, 0x28, 0x00, 0x86, 0x28, + 0x00, 0x86, 0x28, 0x00, 0x86, 0x28, 0x00, 0x86, + 0x28, 0x00, 0x9f, 0x1e, 0xdd, 0x1a, 0x21, 0x99, + 0x33, 0x00, 0xd8, 0x33, 0x0b, 0xe0, 0x75, 0x33, + 0x19, 0x94, 0x1a, 0x80, 0x33, 0x80, 0x1a, 0x80, + 0x33, 0x98, 0x1a, 0x88, 0x33, 0x83, 0x3b, 0x81, + 0x34, 0x87, 0x1a, 0x83, 0x33, 0x83, 0x1a, 0x00, + 0xd5, 0x39, 0x01, 0x81, 0x3b, 0x81, 0x1a, 0x82, + 0x39, 0x80, 0x1a, 0xd9, 0x41, 0x81, 0x1a, 0x82, + 0x41, 0x04, 0xaa, 0x0e, 0x00, 0xdd, 0x34, 0x00, + 0x8f, 0x1a, 0x9f, 0x0e, 0xa5, 0x1a, 0x08, 0x80, + 0x1a, 0x8f, 0x41, 0x9e, 0x34, 0x00, 0xbf, 0x1a, + 0x9e, 0x34, 0xd0, 0x1a, 0xae, 0x41, 0x80, 0x1a, + 0xd7, 0x41, 0xe0, 0x47, 0x1a, 0xf0, 0x09, 0x5f, + 0x33, 0xbf, 0x1a, 0xf0, 0x41, 0x9f, 0x33, 0xe4, + 0x2c, 0xae, 0x02, 0xb6, 0xae, 0x08, 0xaf, 0x51, + 0xe0, 0xcb, 0xa9, 0x13, 0xdf, 0x1e, 0xd7, 0x08, + 0x07, 0xa1, 0x1a, 0xe0, 0x05, 0x4c, 0x82, 0x1a, + 0xd1, 0x4c, 0x13, 0x8e, 0x4c, 0xac, 0x92, 0x02, + 0x89, 0x1a, 0x05, 0xb7, 0x80, 0x07, 0xc5, 0x86, + 0x07, 0x8b, 0x86, 0x05, 0x9f, 0x21, 0xad, 0x44, + 0x80, 0x1a, 0x80, 0x44, 0xa3, 0x83, 0x0a, 0x80, + 0x83, 0x9c, 0x34, 0x02, 0xcd, 0x3e, 0x00, 0x80, + 0x1a, 0x89, 0x3e, 0x03, 0x81, 0x3e, 0x9e, 0x65, + 0x00, 0xb6, 0x17, 0x08, 0x8d, 0x17, 0x01, 0x89, + 0x17, 0x01, 0x83, 0x17, 0x9f, 0x65, 0xc2, 0x98, + 0x17, 0x84, 0x98, 0x96, 0x5c, 0x09, 0x85, 0x28, + 0x01, 0x85, 0x28, 0x01, 0x85, 0x28, 0x08, 0x86, + 0x28, 0x00, 0x86, 0x28, 0x00, 0xaa, 0x4c, 0x80, + 0x1a, 0x88, 0x4c, 0x80, 0x2e, 0x83, 0x4c, 0x81, + 0x1a, 0x03, 0xcf, 0x18, 0xad, 0x5c, 0x01, 0x89, + 0x5c, 0x05, 0xf0, 0x1b, 0x43, 0x34, 0x0b, 0x96, + 0x34, 0x03, 0xb0, 0x34, 0x70, 0x10, 0xa3, 0xe1, + 0x0d, 0x33, 0x01, 0xe0, 0x09, 0x33, 0x25, 0x86, + 0x4c, 0x0b, 0x84, 0x05, 0x04, 0x99, 0x38, 0x00, + 0x84, 0x38, 0x00, 0x80, 0x38, 0x00, 0x81, 0x38, + 0x00, 0x81, 0x38, 0x00, 0x89, 0x38, 0xe1, 0x8d, + 0x04, 0x81, 0x1a, 0xe0, 0x2f, 0x04, 0x1f, 0x8f, + 0x04, 0x8f, 0x3b, 0x89, 0x1a, 0x05, 0x8d, 0x3b, + 0x81, 0x1e, 0xa2, 0x1a, 0x00, 0x92, 0x1a, 0x00, + 0x83, 0x1a, 0x03, 0x84, 0x04, 0x00, 0xe0, 0x26, + 0x04, 0x01, 0x80, 0x1a, 0x00, 0x9f, 0x1a, 0x99, + 0x4c, 0x85, 0x1a, 0x99, 0x4c, 0x8a, 0x1a, 0x89, + 0x41, 0x80, 0x1a, 0xac, 0x41, 0x81, 0x1a, 0x9e, + 0x34, 0x02, 0x85, 0x34, 0x01, 0x85, 0x34, 0x01, + 0x85, 0x34, 0x01, 0x82, 0x34, 0x02, 0x86, 0x1a, + 0x00, 0x86, 0x1a, 0x09, 0x84, 0x1a, 0x01, 0x8b, + 0x50, 0x00, 0x99, 0x50, 0x00, 0x92, 0x50, 0x00, + 0x81, 0x50, 0x00, 0x8e, 0x50, 0x01, 0x8d, 0x50, + 0x21, 0xe0, 0x1a, 0x50, 0x04, 0x82, 0x1a, 0x03, + 0xac, 0x1a, 0x02, 0x88, 0x1a, 0xce, 0x2e, 0x00, + 0x8c, 0x1a, 0x02, 0x80, 0x2e, 0x2e, 0xac, 0x1a, + 0x80, 0x3b, 0x60, 0x21, 0x9c, 0x52, 0x02, 0xb0, + 0x14, 0x0e, 0x80, 0x3b, 0x9a, 0x1a, 0x03, 0xa3, + 0x72, 0x08, 0x82, 0x72, 0x9a, 0x2b, 0x04, 0xaa, + 0x74, 0x04, 0x9d, 0xa8, 0x00, 0x80, 0xa8, 0xa3, + 0x75, 0x03, 0x8d, 0x75, 0x29, 0xcf, 0x20, 0xaf, + 0x88, 0x9d, 0x7c, 0x01, 0x89, 0x7c, 0x05, 0xa3, + 0x7b, 0x03, 0xa3, 0x7b, 0x03, 0xa7, 0x26, 0x07, + 0xb3, 0x15, 0x0a, 0x80, 0x15, 0x8a, 0xaa, 0x00, + 0x8e, 0xaa, 0x00, 0x86, 0xaa, 0x00, 0x81, 0xaa, + 0x00, 0x8a, 0xaa, 0x00, 0x8e, 0xaa, 0x00, 0x86, + 0xaa, 0x00, 0x81, 0xaa, 0x02, 0xb3, 0xa4, 0x0b, + 0xe0, 0xd6, 0x4f, 0x08, 0x95, 0x4f, 0x09, 0x87, + 0x4f, 0x17, 0x85, 0x4c, 0x00, 0xa9, 0x4c, 0x00, + 0x88, 0x4c, 0x44, 0x85, 0x1d, 0x01, 0x80, 0x1d, + 0x00, 0xab, 0x1d, 0x00, 0x81, 0x1d, 0x02, 0x80, + 0x1d, 0x01, 0x80, 0x1d, 0x95, 0x3a, 0x00, 0x88, + 0x3a, 0x9f, 0x7e, 0x9e, 0x66, 0x07, 0x88, 0x66, + 0x2f, 0x92, 0x37, 0x00, 0x81, 0x37, 0x04, 0x84, + 0x37, 0x9b, 0x81, 0x02, 0x80, 0x81, 0x99, 0x53, + 0x04, 0x80, 0x53, 0x99, 0x8a, 0x25, 0x9f, 0x5f, + 0x97, 0x5e, 0x03, 0x93, 0x5e, 0x01, 0xad, 0x5e, + 0x83, 0x45, 0x00, 0x81, 0x45, 0x04, 0x87, 0x45, + 0x00, 0x82, 0x45, 0x00, 0x9c, 0x45, 0x01, 0x82, + 0x45, 0x03, 0x89, 0x45, 0x06, 0x88, 0x45, 0x06, + 0x9f, 0x77, 0x9f, 0x73, 0x1f, 0xa6, 0x58, 0x03, + 0x8b, 0x58, 0x08, 0xb5, 0x06, 0x02, 0x86, 0x06, + 0x95, 0x3d, 0x01, 0x87, 0x3d, 0x92, 0x3c, 0x04, + 0x87, 0x3c, 0x91, 0x82, 0x06, 0x83, 0x82, 0x0b, + 0x86, 0x82, 0x4f, 0xc8, 0x78, 0x36, 0xb2, 0x71, + 0x0c, 0xb2, 0x71, 0x06, 0x85, 0x71, 0xa7, 0x35, + 0x07, 0x89, 0x35, 0x05, 0xa5, 0x2c, 0x02, 0x9c, + 0x2c, 0x07, 0x81, 0x2c, 0x60, 0x6f, 0x9e, 0x04, + 0x00, 0xa9, 0xad, 0x00, 0x82, 0xad, 0x01, 0x81, + 0xad, 0x0f, 0x85, 0x04, 0x07, 0x88, 0x04, 0x20, + 0x85, 0x04, 0xa7, 0x76, 0x07, 0xa9, 0x8d, 0x15, + 0x99, 0x79, 0x25, 0x9b, 0x19, 0x13, 0x96, 0x27, + 0x08, 0xcd, 0x0f, 0x03, 0xa3, 0x0f, 0x08, 0x80, + 0x0f, 0xc2, 0x3f, 0x09, 0x80, 0x3f, 0x01, 0x98, + 0x8e, 0x06, 0x89, 0x8e, 0x05, 0xb4, 0x16, 0x00, + 0x91, 0x16, 0x07, 0xa6, 0x55, 0x08, 0xdf, 0x87, + 0x00, 0x93, 0x8c, 0x0a, 0x91, 0x47, 0x00, 0xae, + 0x47, 0x3d, 0x86, 0x64, 0x00, 0x80, 0x64, 0x00, + 0x83, 0x64, 0x00, 0x8e, 0x64, 0x00, 0x8a, 0x64, + 0x05, 0xba, 0x49, 0x04, 0x89, 0x49, 0x05, 0x83, + 0x2d, 0x00, 0x87, 0x2d, 0x01, 0x81, 0x2d, 0x01, + 0x95, 0x2d, 0x00, 0x86, 0x2d, 0x00, 0x81, 0x2d, + 0x00, 0x84, 0x2d, 0x00, 0x80, 0x3b, 0x88, 0x2d, + 0x01, 0x81, 0x2d, 0x01, 0x82, 0x2d, 0x01, 0x80, + 0x2d, 0x05, 0x80, 0x2d, 0x04, 0x86, 0x2d, 0x01, + 0x86, 0x2d, 0x02, 0x84, 0x2d, 0x0a, 0x89, 0xa7, + 0x00, 0x80, 0xa7, 0x01, 0x80, 0xa7, 0x00, 0xa5, + 0xa7, 0x00, 0x89, 0xa7, 0x00, 0x80, 0xa7, 0x01, + 0x80, 0xa7, 0x00, 0x83, 0xa7, 0x00, 0x89, 0xa7, + 0x00, 0x81, 0xa7, 0x07, 0x81, 0xa7, 0x1c, 0xdb, + 0x6a, 0x00, 0x84, 0x6a, 0x1d, 0xc7, 0xa2, 0x07, + 0x89, 0xa2, 0x60, 0x45, 0xb5, 0x89, 0x01, 0xa5, + 0x89, 0x21, 0xc4, 0x61, 0x0a, 0x89, 0x61, 0x05, + 0x8c, 0x62, 0x12, 0xb9, 0x9a, 0x05, 0x89, 0x9a, + 0x05, 0x93, 0x65, 0x1b, 0x9a, 0x02, 0x01, 0x8e, + 0x02, 0x03, 0x96, 0x02, 0x60, 0x58, 0xbb, 0x23, + 0x60, 0x03, 0xd2, 0xac, 0x0b, 0x80, 0xac, 0x86, + 0x22, 0x01, 0x80, 0x22, 0x01, 0x87, 0x22, 0x00, + 0x81, 0x22, 0x00, 0x9d, 0x22, 0x00, 0x81, 0x22, + 0x01, 0x8b, 0x22, 0x08, 0x89, 0x22, 0x45, 0x87, + 0x68, 0x01, 0xad, 0x68, 0x01, 0x8a, 0x68, 0x1a, + 0xc7, 0xaf, 0x07, 0xd2, 0x8f, 0x0c, 0x8f, 0x13, + 0xb8, 0x7f, 0x06, 0x89, 0x21, 0x55, 0x87, 0x87, + 0x57, 0xa1, 0x91, 0x0d, 0x89, 0x91, 0x05, 0x88, + 0x0d, 0x00, 0xac, 0x0d, 0x00, 0x8d, 0x0d, 0x09, + 0x9c, 0x0d, 0x02, 0x9f, 0x59, 0x01, 0x95, 0x59, + 0x00, 0x8d, 0x59, 0x48, 0x86, 0x5a, 0x00, 0x81, + 0x5a, 0x00, 0xab, 0x5a, 0x02, 0x80, 0x5a, 0x00, + 0x81, 0x5a, 0x00, 0x88, 0x5a, 0x07, 0x89, 0x5a, + 0x05, 0x85, 0x30, 0x00, 0x81, 0x30, 0x00, 0xa4, + 0x30, 0x00, 0x81, 0x30, 0x00, 0x85, 0x30, 0x06, + 0x89, 0x30, 0x05, 0xab, 0xa5, 0x03, 0x89, 0xa5, + 0x60, 0x95, 0x98, 0x54, 0x06, 0x90, 0x43, 0x00, + 0xa8, 0x43, 0x02, 0x9c, 0x43, 0x54, 0x80, 0x51, + 0x0e, 0xb1, 0x9b, 0x0c, 0x80, 0x9b, 0xe3, 0x39, + 0x1c, 0x60, 0x05, 0xe0, 0x0e, 0x1c, 0x00, 0x84, + 0x1c, 0x0a, 0xe0, 0x63, 0x1c, 0x69, 0xeb, 0xe0, + 0x02, 0x1f, 0x0c, 0xe3, 0xf5, 0x25, 0x09, 0xef, + 0x3a, 0x25, 0x04, 0xe1, 0xe6, 0x03, 0x70, 0x0a, + 0x58, 0xb9, 0x32, 0x66, 0x65, 0xe1, 0xd8, 0x08, + 0x06, 0x9e, 0x63, 0x00, 0x89, 0x63, 0x03, 0x81, + 0x63, 0xce, 0xa3, 0x00, 0x89, 0xa3, 0x05, 0x9d, + 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x7d, 0x09, + 0x89, 0x7d, 0x00, 0x86, 0x7d, 0x00, 0x94, 0x7d, + 0x04, 0x92, 0x7d, 0x61, 0x4f, 0xb9, 0x4a, 0x60, + 0x65, 0xda, 0x5b, 0x04, 0x98, 0x0c, 0x01, 0x98, + 0x0c, 0x2b, 0xca, 0x60, 0x03, 0xb8, 0x60, 0x06, + 0x90, 0x60, 0x3f, 0x80, 0x9c, 0x80, 0x6c, 0x81, + 0x33, 0x80, 0x48, 0x0a, 0x86, 0x33, 0x08, 0xf0, + 0x0a, 0x9f, 0x9c, 0xe1, 0x75, 0x48, 0x28, 0x80, + 0x48, 0x9e, 0x9c, 0x60, 0x00, 0xe0, 0x12, 0x9c, + 0x70, 0x11, 0x9c, 0x83, 0x41, 0x00, 0x86, 0x41, + 0x00, 0x81, 0x41, 0x00, 0x80, 0x41, 0xe0, 0xbe, + 0x39, 0x82, 0x41, 0x0e, 0x80, 0x39, 0x1c, 0x82, + 0x39, 0x01, 0x80, 0x41, 0x0d, 0x83, 0x41, 0x07, + 0xe1, 0x2b, 0x6c, 0x68, 0xa3, 0xe0, 0x0a, 0x24, + 0x04, 0x8c, 0x24, 0x02, 0x88, 0x24, 0x06, 0x89, + 0x24, 0x01, 0x83, 0x24, 0x83, 0x1a, 0x6e, 0xfb, + 0xe0, 0x9c, 0x1a, 0x02, 0xe1, 0x53, 0x1a, 0x05, + 0x96, 0x1a, 0x0e, 0x90, 0x1a, 0x0e, 0xad, 0x3b, + 0x01, 0x96, 0x3b, 0x08, 0xe0, 0x13, 0x1a, 0x3b, + 0xe0, 0x95, 0x1a, 0x09, 0xa6, 0x1a, 0x01, 0xbd, + 0x1a, 0x82, 0x3b, 0x90, 0x1a, 0x87, 0x3b, 0x81, + 0x1a, 0x86, 0x3b, 0x9d, 0x1a, 0x83, 0x3b, 0xbc, + 0x1a, 0x14, 0xc5, 0x2e, 0x60, 0x19, 0x93, 0x1a, + 0x0b, 0x93, 0x1a, 0x0b, 0xd6, 0x1a, 0x08, 0x98, + 0x1a, 0x60, 0x26, 0xd4, 0x1a, 0x00, 0xc6, 0x1a, + 0x00, 0x81, 0x1a, 0x01, 0x80, 0x1a, 0x01, 0x81, + 0x1a, 0x01, 0x83, 0x1a, 0x00, 0x8b, 0x1a, 0x00, + 0x80, 0x1a, 0x00, 0x86, 0x1a, 0x00, 0xc0, 0x1a, + 0x00, 0x83, 0x1a, 0x01, 0x87, 0x1a, 0x00, 0x86, + 0x1a, 0x00, 0x9b, 0x1a, 0x00, 0x83, 0x1a, 0x00, + 0x84, 0x1a, 0x00, 0x80, 0x1a, 0x02, 0x86, 0x1a, + 0x00, 0xe0, 0xf3, 0x1a, 0x01, 0xe0, 0xc3, 0x1a, + 0x01, 0xb1, 0x1a, 0xe2, 0x2b, 0x8b, 0x0e, 0x84, + 0x8b, 0x00, 0x8e, 0x8b, 0x63, 0xef, 0x9e, 0x4c, + 0x05, 0x85, 0x4c, 0x60, 0x74, 0x86, 0x2a, 0x00, + 0x90, 0x2a, 0x01, 0x86, 0x2a, 0x00, 0x81, 0x2a, + 0x00, 0x84, 0x2a, 0x04, 0xbd, 0x1e, 0x20, 0x80, + 0x1e, 0x60, 0x0f, 0xac, 0x6d, 0x02, 0x8d, 0x6d, + 0x01, 0x89, 0x6d, 0x03, 0x81, 0x6d, 0x60, 0xdf, + 0x9e, 0xa6, 0x10, 0xb9, 0xab, 0x04, 0x80, 0xab, + 0x61, 0x6f, 0xa9, 0x67, 0x60, 0x75, 0xaa, 0x70, + 0x03, 0x80, 0x70, 0x60, 0x5f, 0x9e, 0x99, 0x00, + 0x95, 0x99, 0x07, 0x81, 0x99, 0x60, 0x7f, 0x86, + 0x28, 0x00, 0x83, 0x28, 0x00, 0x81, 0x28, 0x00, + 0x8e, 0x28, 0x00, 0xe0, 0x64, 0x5d, 0x01, 0x8f, + 0x5d, 0x28, 0xcb, 0x01, 0x03, 0x89, 0x01, 0x03, + 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x1a, 0x4b, 0xbc, + 0x1a, 0x60, 0x61, 0x83, 0x04, 0x00, 0x9a, 0x04, + 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, 0x01, 0x80, + 0x04, 0x00, 0x89, 0x04, 0x00, 0x83, 0x04, 0x00, + 0x80, 0x04, 0x00, 0x80, 0x04, 0x05, 0x80, 0x04, + 0x03, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, + 0x04, 0x00, 0x82, 0x04, 0x00, 0x81, 0x04, 0x00, + 0x80, 0x04, 0x01, 0x80, 0x04, 0x00, 0x80, 0x04, + 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, + 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, 0x01, + 0x83, 0x04, 0x00, 0x86, 0x04, 0x00, 0x83, 0x04, + 0x00, 0x83, 0x04, 0x00, 0x80, 0x04, 0x00, 0x89, + 0x04, 0x00, 0x90, 0x04, 0x04, 0x82, 0x04, 0x00, + 0x84, 0x04, 0x00, 0x90, 0x04, 0x33, 0x81, 0x04, + 0x60, 0xad, 0xab, 0x1a, 0x03, 0xe0, 0x03, 0x1a, + 0x0b, 0x8e, 0x1a, 0x01, 0x8e, 0x1a, 0x00, 0x8e, + 0x1a, 0x00, 0xa4, 0x1a, 0x09, 0xe0, 0x4d, 0x1a, + 0x37, 0x99, 0x1a, 0x80, 0x39, 0x81, 0x1a, 0x0c, + 0xab, 0x1a, 0x03, 0x88, 0x1a, 0x06, 0x81, 0x1a, + 0x0d, 0x85, 0x1a, 0x60, 0x39, 0xe3, 0x78, 0x1a, + 0x02, 0x90, 0x1a, 0x02, 0x8c, 0x1a, 0x02, 0xe0, + 0x79, 0x1a, 0x05, 0x8b, 0x1a, 0x03, 0x80, 0x1a, + 0x0e, 0x8b, 0x1a, 0x03, 0xb7, 0x1a, 0x07, 0x89, + 0x1a, 0x05, 0xa7, 0x1a, 0x07, 0x9d, 0x1a, 0x01, + 0x8b, 0x1a, 0x03, 0x81, 0x1a, 0x0d, 0x88, 0x1a, + 0x26, 0xe0, 0xf7, 0x1a, 0x07, 0x8d, 0x1a, 0x01, + 0x8c, 0x1a, 0x02, 0x8a, 0x1a, 0x02, 0xb8, 0x1a, + 0x00, 0x80, 0x1a, 0x03, 0x8f, 0x1a, 0x01, 0x8b, + 0x1a, 0x03, 0x89, 0x1a, 0x06, 0xe0, 0x32, 0x1a, + 0x00, 0xe0, 0x06, 0x1a, 0x63, 0xa4, 0xf0, 0x96, + 0x7f, 0x33, 0x1f, 0xf0, 0x00, 0xbd, 0x33, 0x01, + 0xf0, 0x06, 0x2d, 0x33, 0x01, 0xf0, 0x0c, 0xd0, + 0x33, 0x0e, 0xe2, 0x0d, 0x33, 0x69, 0x41, 0xe1, + 0xbd, 0x33, 0x65, 0x81, 0xf0, 0x02, 0xea, 0x33, + 0x04, 0xf0, 0x10, 0xc9, 0x33, 0x7a, 0xbb, 0x26, + 0x80, 0x1a, 0x1d, 0xdf, 0x1a, 0x60, 0x1f, 0xe0, + 0x8f, 0x3b, +}; + +static const uint8_t unicode_script_ext_table[1278] = { + 0x80, 0x36, 0x00, 0x00, 0x10, 0x06, 0x14, 0x1b, + 0x24, 0x26, 0x29, 0x2a, 0x30, 0x2b, 0x2e, 0x33, + 0x4c, 0x53, 0x55, 0x74, 0x88, 0x81, 0x83, 0x00, + 0x00, 0x07, 0x0b, 0x1e, 0x21, 0x4c, 0x51, 0x9f, + 0xa6, 0x09, 0x00, 0x00, 0x02, 0x0e, 0x4c, 0x00, + 0x00, 0x02, 0x02, 0x0e, 0x4c, 0x00, 0x00, 0x00, + 0x02, 0x4c, 0x51, 0x08, 0x00, 0x00, 0x02, 0x4c, + 0x9f, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x4c, 0x25, + 0x00, 0x00, 0x08, 0x18, 0x1b, 0x1e, 0x2e, 0x4c, + 0x74, 0x91, 0x96, 0x00, 0x08, 0x18, 0x1e, 0x2e, + 0x4c, 0x7b, 0x91, 0x96, 0xa4, 0x00, 0x04, 0x18, + 0x1e, 0x4c, 0xa1, 0x00, 0x05, 0x2a, 0x4c, 0x91, + 0x93, 0x9f, 0x00, 0x0b, 0x15, 0x18, 0x1b, 0x1e, + 0x2b, 0x2e, 0x4c, 0x7b, 0x93, 0xa1, 0xa4, 0x00, + 0x06, 0x1b, 0x26, 0x2a, 0x2b, 0x41, 0x4c, 0x00, + 0x05, 0x1e, 0x2e, 0x4c, 0x74, 0xa1, 0x00, 0x09, + 0x1b, 0x24, 0x38, 0x4c, 0x74, 0x93, 0x96, 0xa1, + 0xa4, 0x00, 0x0b, 0x05, 0x1e, 0x24, 0x2b, 0x2e, + 0x38, 0x4c, 0x74, 0x93, 0x96, 0xa1, 0x00, 0x02, + 0x4c, 0xa1, 0x00, 0x03, 0x24, 0x4c, 0x93, 0x00, + 0x04, 0x18, 0x1e, 0x4c, 0x7b, 0x00, 0x03, 0x18, + 0x4c, 0x96, 0x00, 0x02, 0x4c, 0x91, 0x00, 0x02, + 0x28, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x4c, 0x91, + 0x00, 0x03, 0x1e, 0x4c, 0xa4, 0x00, 0x00, 0x00, + 0x04, 0x2e, 0x4c, 0x74, 0xa4, 0x0e, 0x00, 0x00, + 0x06, 0x18, 0x24, 0x41, 0x4c, 0x93, 0xa1, 0x00, + 0x04, 0x18, 0x24, 0x4c, 0x93, 0x00, 0x02, 0x4c, + 0x93, 0x06, 0x00, 0x00, 0x03, 0x4c, 0x91, 0x93, + 0x00, 0x02, 0x4c, 0x93, 0x00, 0x00, 0x00, 0x03, + 0x18, 0x4c, 0x93, 0x00, 0x07, 0x15, 0x18, 0x2b, + 0x4c, 0x91, 0x93, 0x9f, 0x0f, 0x00, 0x00, 0x01, + 0x2e, 0x01, 0x00, 0x00, 0x01, 0x2e, 0x11, 0x00, + 0x00, 0x02, 0x4c, 0x7b, 0x04, 0x00, 0x00, 0x03, + 0x15, 0x4c, 0xa4, 0x03, 0x00, 0x0c, 0x01, 0x4c, + 0x03, 0x00, 0x01, 0x02, 0x1b, 0x2e, 0x80, 0x8c, + 0x00, 0x00, 0x02, 0x1e, 0x74, 0x00, 0x02, 0x1e, + 0x2a, 0x01, 0x02, 0x1e, 0x4c, 0x00, 0x02, 0x1e, + 0x2a, 0x80, 0x80, 0x00, 0x00, 0x03, 0x05, 0x29, + 0x2a, 0x80, 0x01, 0x00, 0x00, 0x07, 0x04, 0x2c, + 0x6b, 0x35, 0x93, 0x9e, 0xad, 0x0d, 0x00, 0x00, + 0x07, 0x04, 0x2c, 0x6b, 0x35, 0x93, 0x9e, 0xad, + 0x00, 0x03, 0x04, 0x93, 0x9e, 0x01, 0x00, 0x00, + 0x08, 0x01, 0x04, 0x2c, 0x6b, 0x35, 0x93, 0x9e, + 0xad, 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x57, + 0x58, 0x79, 0x82, 0x35, 0x8d, 0x93, 0x09, 0x00, + 0x0a, 0x02, 0x04, 0x93, 0x09, 0x00, 0x09, 0x03, + 0x04, 0x9e, 0xad, 0x05, 0x00, 0x00, 0x02, 0x04, + 0x93, 0x62, 0x00, 0x00, 0x02, 0x04, 0x35, 0x81, + 0xfb, 0x00, 0x00, 0x0f, 0x0b, 0x21, 0x2d, 0x2f, + 0x31, 0x40, 0x4c, 0x56, 0x68, 0x6a, 0x7a, 0x87, + 0x9b, 0x9d, 0xa2, 0x00, 0x0d, 0x0b, 0x21, 0x2d, + 0x2f, 0x31, 0x40, 0x4c, 0x56, 0x6a, 0x7a, 0x9b, + 0x9d, 0xa2, 0x10, 0x00, 0x00, 0x15, 0x0b, 0x21, + 0x23, 0x30, 0x5a, 0x2d, 0x2f, 0x31, 0x40, 0x55, + 0x56, 0x68, 0x70, 0x7a, 0x49, 0x8c, 0x92, 0x9a, + 0x9b, 0x9d, 0xa2, 0x00, 0x17, 0x0b, 0x21, 0x23, + 0x30, 0x5a, 0x2d, 0x2f, 0x32, 0x31, 0x40, 0x4e, + 0x55, 0x56, 0x68, 0x70, 0x7a, 0x49, 0x8c, 0x92, + 0x9a, 0x9b, 0x9d, 0xa2, 0x09, 0x04, 0x21, 0x23, + 0x3f, 0x55, 0x75, 0x00, 0x09, 0x03, 0x0b, 0x16, + 0x92, 0x75, 0x00, 0x09, 0x02, 0x31, 0x64, 0x75, + 0x00, 0x09, 0x02, 0x2f, 0x47, 0x80, 0x75, 0x00, + 0x0d, 0x02, 0x2d, 0x9b, 0x80, 0x71, 0x00, 0x09, + 0x03, 0x40, 0x68, 0xa7, 0x82, 0xcf, 0x00, 0x09, + 0x03, 0x16, 0x65, 0x96, 0x80, 0x30, 0x00, 0x00, + 0x03, 0x29, 0x2a, 0x4c, 0x85, 0x6e, 0x00, 0x02, + 0x01, 0x84, 0x46, 0x00, 0x01, 0x04, 0x12, 0x36, + 0x95, 0x94, 0x80, 0x4a, 0x00, 0x01, 0x02, 0x62, + 0x80, 0x00, 0x00, 0x00, 0x02, 0x62, 0x80, 0x84, + 0x49, 0x00, 0x00, 0x04, 0x0b, 0x21, 0x2d, 0x40, + 0x00, 0x01, 0x21, 0x00, 0x04, 0x0b, 0x21, 0x2d, + 0x40, 0x00, 0x03, 0x21, 0x2d, 0x40, 0x00, 0x01, + 0x21, 0x00, 0x05, 0x0b, 0x21, 0x6a, 0x9d, 0xa2, + 0x00, 0x03, 0x0b, 0x21, 0x9d, 0x00, 0x03, 0x21, + 0x6a, 0x87, 0x00, 0x04, 0x0b, 0x21, 0x6a, 0x9d, + 0x00, 0x02, 0x21, 0x87, 0x00, 0x06, 0x21, 0x40, + 0x56, 0x7a, 0x9b, 0x9d, 0x00, 0x01, 0x21, 0x01, + 0x02, 0x21, 0x87, 0x01, 0x01, 0x21, 0x00, 0x02, + 0x21, 0x87, 0x00, 0x02, 0x0b, 0x21, 0x00, 0x03, + 0x21, 0x6a, 0xa2, 0x05, 0x01, 0x21, 0x00, 0x03, + 0x21, 0x68, 0x6a, 0x00, 0x03, 0x0b, 0x21, 0x87, + 0x00, 0x02, 0x21, 0x6a, 0x00, 0x01, 0x21, 0x00, + 0x04, 0x0b, 0x21, 0x6a, 0x87, 0x03, 0x01, 0x21, + 0x00, 0x0b, 0x0b, 0x21, 0x2d, 0x40, 0x56, 0x68, + 0x7a, 0x8c, 0x9d, 0xa2, 0xa7, 0x00, 0x02, 0x21, + 0x2d, 0x00, 0x04, 0x21, 0x2d, 0x40, 0xa7, 0x01, + 0x02, 0x0b, 0x21, 0x00, 0x01, 0x0b, 0x01, 0x02, + 0x21, 0x2d, 0x00, 0x01, 0x68, 0x80, 0x44, 0x00, + 0x01, 0x01, 0x2e, 0x35, 0x00, 0x00, 0x03, 0x1e, + 0x4c, 0x93, 0x00, 0x00, 0x00, 0x01, 0x93, 0x81, + 0xb3, 0x00, 0x00, 0x03, 0x4c, 0x62, 0x80, 0x1e, + 0x00, 0x00, 0x02, 0x01, 0x04, 0x09, 0x00, 0x00, + 0x06, 0x14, 0x29, 0x2a, 0x71, 0x52, 0x78, 0x01, + 0x00, 0x00, 0x04, 0x14, 0x2e, 0x71, 0x5f, 0x80, + 0x11, 0x00, 0x00, 0x03, 0x21, 0x2d, 0x4c, 0x8c, + 0xa5, 0x00, 0x00, 0x02, 0x1b, 0x4c, 0x17, 0x00, + 0x00, 0x02, 0x06, 0x78, 0x00, 0x07, 0x06, 0x14, + 0x29, 0x71, 0x3f, 0x53, 0x85, 0x09, 0x00, 0x00, + 0x01, 0x24, 0x03, 0x00, 0x00, 0x03, 0x01, 0x04, + 0x71, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x2a, 0x81, + 0x2b, 0x00, 0x0f, 0x02, 0x33, 0x9c, 0x00, 0x00, + 0x00, 0x07, 0x0e, 0x34, 0x33, 0x39, 0x41, 0x62, + 0xae, 0x00, 0x08, 0x0e, 0x34, 0x33, 0x39, 0x41, + 0x62, 0x80, 0xae, 0x00, 0x05, 0x0e, 0x34, 0x33, + 0x39, 0x41, 0x01, 0x00, 0x00, 0x01, 0x33, 0x00, + 0x00, 0x01, 0x08, 0x0e, 0x34, 0x33, 0x39, 0x41, + 0x62, 0xa0, 0xae, 0x01, 0x09, 0x0e, 0x34, 0x33, + 0x39, 0x41, 0x51, 0x62, 0xa0, 0xae, 0x05, 0x06, + 0x0e, 0x34, 0x33, 0x39, 0x41, 0xae, 0x00, 0x00, + 0x00, 0x05, 0x0e, 0x34, 0x33, 0x39, 0x41, 0x07, + 0x06, 0x0e, 0x34, 0x33, 0x39, 0x41, 0xae, 0x03, + 0x05, 0x0e, 0x34, 0x33, 0x39, 0x41, 0x09, 0x00, + 0x03, 0x02, 0x0e, 0x33, 0x01, 0x00, 0x00, 0x05, + 0x0e, 0x34, 0x33, 0x39, 0x41, 0x04, 0x02, 0x39, + 0x41, 0x00, 0x00, 0x00, 0x05, 0x0e, 0x34, 0x33, + 0x39, 0x41, 0x03, 0x00, 0x01, 0x03, 0x33, 0x39, + 0x41, 0x01, 0x01, 0x33, 0x58, 0x00, 0x03, 0x02, + 0x39, 0x41, 0x02, 0x00, 0x00, 0x02, 0x39, 0x41, + 0x59, 0x00, 0x00, 0x06, 0x0e, 0x34, 0x33, 0x39, + 0x41, 0xae, 0x00, 0x02, 0x39, 0x41, 0x80, 0x12, + 0x00, 0x0f, 0x01, 0x33, 0x1f, 0x00, 0x25, 0x01, + 0x33, 0x08, 0x00, 0x00, 0x02, 0x33, 0x9c, 0x2f, + 0x00, 0x27, 0x01, 0x33, 0x37, 0x00, 0x30, 0x01, + 0x33, 0x0e, 0x00, 0x0b, 0x01, 0x33, 0x32, 0x00, + 0x00, 0x01, 0x33, 0x57, 0x00, 0x18, 0x01, 0x33, + 0x09, 0x00, 0x04, 0x01, 0x33, 0x5f, 0x00, 0x1e, + 0x01, 0x33, 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, + 0x1e, 0x2a, 0x80, 0x0f, 0x00, 0x07, 0x02, 0x33, + 0x4c, 0x80, 0xa7, 0x00, 0x02, 0x10, 0x21, 0x23, + 0x2f, 0x31, 0x47, 0x40, 0x3f, 0x55, 0x56, 0x61, + 0x68, 0x87, 0x49, 0x9a, 0xa2, 0xa7, 0x02, 0x0f, + 0x21, 0x23, 0x2f, 0x31, 0x47, 0x40, 0x3f, 0x55, + 0x61, 0x68, 0x87, 0x49, 0x9a, 0xa2, 0xa7, 0x01, + 0x0b, 0x21, 0x23, 0x2f, 0x31, 0x47, 0x3f, 0x55, + 0x61, 0x49, 0x9a, 0xa2, 0x00, 0x0c, 0x21, 0x23, + 0x2f, 0x31, 0x47, 0x3f, 0x55, 0x61, 0x87, 0x49, + 0x9a, 0xa2, 0x00, 0x0b, 0x21, 0x23, 0x2f, 0x31, + 0x47, 0x3f, 0x55, 0x61, 0x49, 0x9a, 0xa2, 0x80, + 0x36, 0x00, 0x00, 0x03, 0x0b, 0x21, 0xa7, 0x00, + 0x00, 0x00, 0x02, 0x21, 0x9b, 0x39, 0x00, 0x00, + 0x03, 0x44, 0x4c, 0x65, 0x80, 0x1f, 0x00, 0x00, + 0x02, 0x11, 0x3e, 0xc0, 0x12, 0xed, 0x00, 0x01, + 0x02, 0x04, 0x6b, 0x80, 0x31, 0x00, 0x00, 0x02, + 0x04, 0x9e, 0x09, 0x00, 0x00, 0x02, 0x04, 0x9e, + 0x46, 0x00, 0x01, 0x05, 0x0e, 0x34, 0x33, 0x39, + 0x41, 0x80, 0x99, 0x00, 0x04, 0x06, 0x0e, 0x34, + 0x33, 0x39, 0x41, 0xae, 0x09, 0x00, 0x00, 0x02, + 0x39, 0x41, 0x2c, 0x00, 0x01, 0x02, 0x39, 0x41, + 0x80, 0xdf, 0x00, 0x01, 0x03, 0x1f, 0x1d, 0x50, + 0x00, 0x02, 0x1d, 0x50, 0x03, 0x00, 0x2c, 0x03, + 0x1d, 0x4f, 0x50, 0x02, 0x00, 0x08, 0x02, 0x1d, + 0x50, 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1b, + 0x87, 0x75, 0x00, 0x00, 0x02, 0x58, 0x79, 0x87, + 0x8d, 0x00, 0x00, 0x02, 0x2d, 0x9b, 0x00, 0x00, + 0x00, 0x02, 0x2d, 0x9b, 0x36, 0x00, 0x01, 0x02, + 0x2d, 0x9b, 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2d, + 0x9b, 0x00, 0x00, 0x00, 0x02, 0x2d, 0x9b, 0xc0, + 0x5c, 0x4b, 0x00, 0x03, 0x01, 0x24, 0x96, 0x3b, + 0x00, 0x11, 0x01, 0x33, 0x9e, 0x5d, 0x00, 0x01, + 0x01, 0x33, 0xce, 0xcd, 0x2d, 0x00, +}; + +static const uint8_t unicode_prop_Hyphen_table[28] = { + 0xac, 0x80, 0xfe, 0x80, 0x44, 0xdb, 0x80, 0x52, + 0x7a, 0x80, 0x48, 0x08, 0x81, 0x4e, 0x04, 0x80, + 0x42, 0xe2, 0x80, 0x60, 0xcd, 0x66, 0x80, 0x40, + 0xa8, 0x80, 0xd6, 0x80, +}; + +static const uint8_t unicode_prop_Other_Math_table[200] = { + 0xdd, 0x80, 0x43, 0x70, 0x11, 0x80, 0x99, 0x09, + 0x81, 0x5c, 0x1f, 0x80, 0x9a, 0x82, 0x8a, 0x80, + 0x9f, 0x83, 0x97, 0x81, 0x8d, 0x81, 0xc0, 0x8c, + 0x18, 0x11, 0x1c, 0x91, 0x03, 0x01, 0x89, 0x00, + 0x14, 0x28, 0x11, 0x09, 0x02, 0x05, 0x13, 0x24, + 0xca, 0x21, 0x18, 0x08, 0x08, 0x00, 0x21, 0x0b, + 0x0b, 0x91, 0x09, 0x00, 0x06, 0x00, 0x29, 0x41, + 0x21, 0x83, 0x40, 0xa7, 0x08, 0x80, 0x97, 0x80, + 0x90, 0x80, 0x41, 0xbc, 0x81, 0x8b, 0x88, 0x24, + 0x21, 0x09, 0x14, 0x8d, 0x00, 0x01, 0x85, 0x97, + 0x81, 0xb8, 0x00, 0x80, 0x9c, 0x83, 0x88, 0x81, + 0x41, 0x55, 0x81, 0x9e, 0x89, 0x41, 0x92, 0x95, + 0xbe, 0x83, 0x9f, 0x81, 0x60, 0xd4, 0x62, 0x00, + 0x03, 0x80, 0x40, 0xd2, 0x00, 0x80, 0x60, 0xd4, + 0xc0, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, + 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, + 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, + 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x81, + 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00, 0x08, + 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, + 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, +}; + +static const uint8_t unicode_prop_Other_Alphabetic_table[452] = { + 0x43, 0x44, 0x80, 0x9c, 0x8c, 0x42, 0x3f, 0x8d, + 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, + 0x06, 0x8f, 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, + 0xa2, 0x80, 0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a, + 0x88, 0x02, 0x03, 0xe9, 0x80, 0xbb, 0x8b, 0x16, + 0x85, 0x93, 0xb5, 0x09, 0x8e, 0x01, 0x22, 0x89, + 0x81, 0x9c, 0x82, 0xb9, 0x31, 0x09, 0x81, 0x89, + 0x80, 0x89, 0x81, 0x9c, 0x82, 0xb9, 0x23, 0x09, + 0x0b, 0x80, 0x9d, 0x0a, 0x80, 0x8a, 0x82, 0xb9, + 0x38, 0x10, 0x81, 0x94, 0x81, 0x95, 0x13, 0x82, + 0xb9, 0x31, 0x09, 0x81, 0x88, 0x81, 0x89, 0x81, + 0x9d, 0x80, 0xba, 0x22, 0x10, 0x82, 0x89, 0x80, + 0xa7, 0x84, 0xb8, 0x30, 0x10, 0x17, 0x81, 0x8a, + 0x81, 0x9c, 0x82, 0xb9, 0x30, 0x10, 0x17, 0x81, + 0x8a, 0x81, 0x8e, 0x80, 0x8b, 0x83, 0xb9, 0x30, + 0x10, 0x82, 0x89, 0x80, 0x89, 0x81, 0x9c, 0x82, + 0xca, 0x28, 0x00, 0x87, 0x91, 0x81, 0xbc, 0x01, + 0x86, 0x91, 0x80, 0xe2, 0x01, 0x28, 0x81, 0x8f, + 0x80, 0x40, 0xa2, 0x92, 0x88, 0x8a, 0x80, 0xa3, + 0xed, 0x8b, 0x00, 0x0b, 0x96, 0x1b, 0x10, 0x11, + 0x32, 0x83, 0x8c, 0x8b, 0x00, 0x89, 0x83, 0x46, + 0x73, 0x81, 0x9d, 0x81, 0x9d, 0x81, 0x9d, 0x81, + 0xc1, 0x92, 0x40, 0xbb, 0x81, 0xa1, 0x80, 0xf5, + 0x8b, 0x83, 0x88, 0x40, 0xdd, 0x84, 0xb8, 0x89, + 0x81, 0x93, 0xc9, 0x81, 0x8a, 0x82, 0xb0, 0x84, + 0xaf, 0x8e, 0xbb, 0x82, 0x9d, 0x88, 0x09, 0xb8, + 0x8a, 0xb1, 0x92, 0x41, 0x9b, 0xa1, 0x46, 0xc0, + 0xb3, 0x48, 0xf5, 0x9f, 0x60, 0x78, 0x73, 0x87, + 0xa1, 0x81, 0x41, 0x61, 0x07, 0x80, 0x96, 0x84, + 0xd7, 0x81, 0xb1, 0x8f, 0x00, 0xb8, 0x80, 0xa5, + 0x84, 0x9b, 0x8b, 0xac, 0x83, 0xaf, 0x8b, 0xa4, + 0x80, 0xc2, 0x8d, 0x8b, 0x07, 0x81, 0xac, 0x82, + 0xb1, 0x00, 0x11, 0x0c, 0x80, 0xab, 0x24, 0x80, + 0x40, 0xec, 0x87, 0x60, 0x4f, 0x32, 0x80, 0x48, + 0x56, 0x84, 0x46, 0x85, 0x10, 0x0c, 0x83, 0x43, + 0x13, 0x83, 0xc0, 0x80, 0x41, 0x40, 0x81, 0xcc, + 0x82, 0x41, 0x02, 0x82, 0xb4, 0x8d, 0xac, 0x81, + 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc, 0x82, + 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, 0x8c, + 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08, 0x40, + 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81, + 0x89, 0x80, 0x89, 0x81, 0xd3, 0x88, 0x00, 0x08, + 0x03, 0x01, 0xe6, 0x8c, 0x02, 0xe9, 0x91, 0x40, + 0xec, 0x31, 0x86, 0x9c, 0x81, 0xd1, 0x8e, 0x00, + 0xe9, 0x8a, 0xe6, 0x8d, 0x41, 0x00, 0x8c, 0x40, + 0xf6, 0x28, 0x09, 0x0a, 0x00, 0x80, 0x40, 0x8d, + 0x31, 0x2b, 0x80, 0x9b, 0x89, 0xa9, 0x20, 0x83, + 0x91, 0x8a, 0xad, 0x8d, 0x40, 0xc7, 0x87, 0x40, + 0xc6, 0x38, 0x86, 0xd2, 0x95, 0x80, 0x8d, 0xf9, + 0x2a, 0x00, 0x08, 0x10, 0x02, 0x80, 0xc1, 0x20, + 0x08, 0x83, 0x41, 0x5b, 0x83, 0x88, 0x08, 0x80, + 0xaf, 0x32, 0x82, 0x60, 0x41, 0xdc, 0x90, 0x4e, + 0x1f, 0x00, 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c, + 0xab, 0x80, 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e, + 0x01, 0x04, 0xe3, 0x80, 0x46, 0x52, 0x01, 0x06, + 0x0c, 0x80, 0x42, 0x50, 0x80, 0x47, 0xe7, 0x99, + 0x85, 0x99, 0x85, 0x99, +}; + +static const uint8_t unicode_prop_Other_Lowercase_table[68] = { + 0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88, + 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x4d, + 0x80, 0x80, 0x4c, 0x2e, 0xbe, 0x8c, 0x80, 0xa1, + 0xa4, 0x42, 0xb0, 0x80, 0x8c, 0x80, 0x8f, 0x8c, + 0x40, 0xd2, 0x8f, 0x43, 0x4f, 0x99, 0x47, 0x91, + 0x81, 0x60, 0x7a, 0x1d, 0x81, 0x40, 0xd1, 0x80, + 0xff, 0x1a, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, + 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80, 0x88, + 0x60, 0xd8, 0x74, 0xbd, +}; + +static const uint8_t unicode_prop_Other_Uppercase_table[15] = { + 0x60, 0x21, 0x5f, 0x8f, 0x43, 0x45, 0x99, 0x61, + 0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99, +}; + +static const uint8_t unicode_prop_Other_Grapheme_Extend_table[112] = { + 0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80, + 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe7, + 0x00, 0x03, 0x08, 0x81, 0x88, 0x81, 0xe6, 0x80, + 0x97, 0x80, 0xf6, 0x80, 0x8e, 0x80, 0x49, 0x34, + 0x80, 0x9d, 0x80, 0x43, 0xff, 0x04, 0x00, 0x04, + 0x81, 0xe4, 0x80, 0xc6, 0x81, 0x44, 0x17, 0x80, + 0x50, 0x20, 0x81, 0x60, 0x79, 0x22, 0x80, 0xeb, + 0x80, 0x60, 0x55, 0xdc, 0x81, 0x52, 0x1f, 0x80, + 0xf3, 0x80, 0x41, 0x07, 0x80, 0x8d, 0x80, 0x88, + 0x80, 0xdf, 0x80, 0x88, 0x01, 0x00, 0x14, 0x80, + 0x40, 0xdf, 0x80, 0x8b, 0x80, 0x40, 0xf0, 0x80, + 0x41, 0x05, 0x80, 0x42, 0x78, 0x80, 0x8b, 0x80, + 0x46, 0x02, 0x80, 0x60, 0x50, 0xad, 0x81, 0x60, + 0x61, 0x72, 0x0d, 0x85, 0x6c, 0x2e, 0xac, 0xdf, +}; + +static const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = { + 0x43, 0x4e, 0x80, 0x4e, 0x0e, 0x81, 0x46, 0x52, + 0x81, 0x48, 0xae, 0x80, 0x50, 0xfd, 0x80, 0x60, + 0xce, 0x3a, 0x80, 0xce, 0x88, 0x6d, 0x00, 0x06, + 0x00, 0x9d, 0xdf, 0xff, 0x40, 0xef, 0x4e, 0x0f, +}; + +static const uint8_t unicode_prop_Other_ID_Start_table[11] = { + 0x58, 0x84, 0x81, 0x48, 0x90, 0x80, 0x94, 0x80, + 0x4f, 0x6b, 0x81, +}; + +static const uint8_t unicode_prop_Other_ID_Continue_table[22] = { + 0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0, + 0x88, 0x46, 0x67, 0x80, 0x46, 0x30, 0x81, 0x50, + 0xec, 0x80, 0x60, 0xce, 0x68, 0x80, +}; + +static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[19] = { + 0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80, + 0x41, 0x7f, 0x81, 0xcf, 0x80, 0x61, 0x07, 0xd9, + 0x80, 0x8e, 0x80, +}; + +static const uint8_t unicode_prop_XID_Start1_table[31] = { + 0x43, 0x79, 0x80, 0x4a, 0xb7, 0x80, 0xfe, 0x80, + 0x60, 0x21, 0xe6, 0x81, 0x60, 0xcb, 0xc0, 0x85, + 0x41, 0x95, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x41, 0x1e, 0x81, +}; + +static const uint8_t unicode_prop_XID_Continue1_table[23] = { + 0x43, 0x79, 0x80, 0x60, 0x2d, 0x1f, 0x81, 0x60, + 0xcb, 0xc0, 0x85, 0x41, 0x95, 0x81, 0xf3, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +}; + +static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = { + 0x41, 0xc3, 0x08, 0x08, 0x81, 0xa4, 0x81, 0x4e, + 0xdc, 0xaa, 0x0a, 0x4e, 0x87, 0x3f, 0x3f, 0x87, + 0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80, +}; + +static const uint8_t unicode_prop_Changes_When_Casefolded1_table[29] = { + 0x41, 0xef, 0x80, 0x41, 0x9e, 0x80, 0x9e, 0x80, + 0x5a, 0xe4, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, + 0x80, 0xde, 0x06, 0x06, 0x80, 0x8a, 0x09, 0x81, + 0x89, 0x10, 0x81, 0x8d, 0x80, +}; + +static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[449] = { + 0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12, + 0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84, + 0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb, + 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, 0x81, 0x89, + 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, 0x07, 0x80, + 0x9e, 0x80, 0xa0, 0x82, 0x9c, 0x80, 0x42, 0x28, + 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, 0xfb, 0x08, + 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, 0x80, 0x40, + 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, 0x80, 0xa7, + 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, 0x03, 0x03, + 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, 0x26, 0x80, + 0x90, 0x80, 0x88, 0x03, 0x03, 0x03, 0x80, 0x8b, + 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, 0x46, 0x52, + 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, 0x8a, 0x80, + 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, 0xa4, 0x40, + 0xd5, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, 0x80, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xb7, 0x05, 0x00, 0x13, 0x05, 0x11, 0x02, 0x0c, + 0x11, 0x00, 0x00, 0x0c, 0x15, 0x05, 0x08, 0x8f, + 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, 0x00, + 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, 0x80, + 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, 0x01, + 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, 0x05, + 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, 0x40, + 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, 0x34, + 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, 0x82, + 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, 0x80, + 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, 0xd5, + 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, 0x80, + 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, 0x9e, + 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, 0x60, + 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0xff, 0x1a, + 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60, 0x4d, + 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89, 0x00, + 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xc2, 0x00, + 0x97, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb, 0xa0, + 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7, 0x8c, + 0x82, 0x99, 0x95, 0x94, 0x81, 0x8b, 0x80, 0x92, + 0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08, 0x80, + 0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d, 0x0a, + 0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20, 0xa9, + 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x50, 0x31, + 0xa3, 0x44, 0x63, 0x86, 0x8d, 0x87, 0xbf, 0x85, + 0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, + 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, + 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, + 0x80, 0x41, 0x53, 0x81, 0x41, 0x23, 0x81, 0xb1, + 0x48, 0x2f, 0xbd, 0x4d, 0x91, 0x18, 0x9a, 0x01, + 0x00, 0x08, 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, + 0x18, 0x00, 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, + 0x03, 0x00, 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, + 0x80, 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, + 0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, + 0xab, 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, + 0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, + 0xff, +}; + +static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = { + 0xaf, 0x89, 0x35, 0x99, 0x85, +}; + +static const uint8_t unicode_prop_Bidi_Control_table[10] = { + 0x46, 0x1b, 0x80, 0x59, 0xf0, 0x81, 0x99, 0x84, + 0xb6, 0x83, +}; + +static const uint8_t unicode_prop_Dash_table[58] = { + 0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e, + 0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85, + 0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85, + 0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80, + 0x9b, 0x80, 0x41, 0xbd, 0x80, 0x92, 0x80, 0xee, + 0x80, 0x60, 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89, + 0x80, 0x40, 0xa8, 0x80, 0x4e, 0x5f, 0x80, 0x41, + 0x3d, 0x80, +}; + +static const uint8_t unicode_prop_Deprecated_table[23] = { + 0x41, 0x48, 0x80, 0x45, 0x28, 0x80, 0x49, 0x02, + 0x00, 0x80, 0x48, 0x28, 0x81, 0x48, 0xc4, 0x85, + 0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80, +}; + +static const uint8_t unicode_prop_Diacritic_table[447] = { + 0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81, + 0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b, + 0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0, + 0x80, 0xb6, 0xac, 0x00, 0x01, 0x01, 0x00, 0x40, + 0x82, 0x3b, 0x81, 0x40, 0x85, 0x0b, 0x0a, 0x82, + 0xc2, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0xa1, 0x81, + 0xfd, 0x87, 0xa8, 0x89, 0x8f, 0x9b, 0xbc, 0x80, + 0x8f, 0x02, 0x83, 0x9b, 0x80, 0xc9, 0x80, 0x8f, + 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80, 0x8f, + 0x80, 0xae, 0x82, 0xbb, 0x80, 0x8f, 0x06, 0x80, + 0xf6, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80, + 0x8f, 0x80, 0xec, 0x81, 0x8f, 0x80, 0xfb, 0x80, + 0xee, 0x80, 0x8b, 0x28, 0x80, 0xea, 0x80, 0x8c, + 0x84, 0xca, 0x81, 0x9a, 0x00, 0x00, 0x03, 0x81, + 0xc1, 0x10, 0x81, 0xbd, 0x80, 0xef, 0x00, 0x81, + 0xa7, 0x0b, 0x84, 0x98, 0x30, 0x80, 0x89, 0x81, + 0x42, 0xc0, 0x82, 0x43, 0xb3, 0x81, 0x9d, 0x80, + 0x40, 0x93, 0x8a, 0x88, 0x80, 0x41, 0x5a, 0x82, + 0x41, 0x23, 0x80, 0x93, 0x39, 0x80, 0xaf, 0x8e, + 0x81, 0x8a, 0x82, 0x8e, 0x81, 0x8b, 0xc7, 0x80, + 0x8e, 0x80, 0xa5, 0x88, 0xb5, 0x81, 0xb9, 0x80, + 0x8a, 0x81, 0xc1, 0x81, 0xbf, 0x85, 0xd1, 0x98, + 0x18, 0x28, 0x0a, 0xb1, 0xbe, 0xaf, 0xa3, 0x84, + 0x8b, 0xa4, 0x8a, 0x41, 0xbc, 0x00, 0x82, 0x8a, + 0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c, 0x81, 0x4c, + 0xef, 0x82, 0x41, 0x3c, 0x80, 0x41, 0xf9, 0x85, + 0xe8, 0x83, 0xde, 0x80, 0x60, 0x75, 0x71, 0x80, + 0x8b, 0x08, 0x80, 0x9b, 0x81, 0xd1, 0x81, 0x8d, + 0xa1, 0xe5, 0x82, 0xe5, 0x05, 0x81, 0x8b, 0x80, + 0xa4, 0x80, 0x40, 0x96, 0x80, 0x9a, 0x91, 0xb8, + 0x83, 0xa3, 0x80, 0xde, 0x80, 0x8b, 0x80, 0xa3, + 0x80, 0x40, 0x94, 0x82, 0xc0, 0x83, 0xb2, 0x80, + 0xe3, 0x84, 0x88, 0x82, 0xff, 0x81, 0x60, 0x4f, + 0x2f, 0x80, 0x43, 0x00, 0x8f, 0x41, 0x0d, 0x00, + 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2, 0x80, 0x42, + 0xfb, 0x80, 0x44, 0x9e, 0x28, 0xa9, 0x80, 0x88, + 0x42, 0x7c, 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, + 0x3a, 0x85, 0xa5, 0x80, 0x99, 0x84, 0x41, 0x8b, + 0x01, 0x82, 0xc5, 0x8a, 0xb0, 0x83, 0x40, 0xbf, + 0x80, 0xa8, 0x80, 0xc7, 0x81, 0xf7, 0x81, 0xbd, + 0x80, 0xcb, 0x80, 0x88, 0x82, 0xe7, 0x81, 0x40, + 0xb1, 0x81, 0xcf, 0x81, 0x8f, 0x80, 0x97, 0x32, + 0x84, 0xd8, 0x10, 0x81, 0x8c, 0x81, 0xde, 0x02, + 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd, 0x80, + 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81, 0x41, + 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2, 0x80, + 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80, 0x41, + 0x01, 0x00, 0x81, 0xd0, 0x80, 0xc0, 0x80, 0x41, + 0x66, 0x81, 0x96, 0x80, 0x54, 0xeb, 0x8e, 0x60, + 0x2c, 0xd8, 0x80, 0x49, 0xbf, 0x84, 0xba, 0x86, + 0x42, 0x33, 0x81, 0x42, 0x21, 0x90, 0xcf, 0x81, + 0x60, 0x3f, 0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00, + 0xad, 0x81, 0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39, + 0x86, 0x9d, 0x83, 0x4e, 0x81, 0xbd, 0x40, 0xc1, + 0x86, 0x41, 0x76, 0x80, 0xbc, 0x83, 0x42, 0xfd, + 0x81, 0x42, 0xdf, 0x86, 0xec, 0x10, 0x82, +}; + +static const uint8_t unicode_prop_Extender_table[116] = { + 0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d, + 0x80, 0x41, 0xb8, 0x80, 0x42, 0x75, 0x80, 0x40, + 0x88, 0x80, 0xd8, 0x80, 0x42, 0xef, 0x80, 0xfe, + 0x80, 0x49, 0x42, 0x80, 0xb7, 0x80, 0x42, 0x62, + 0x80, 0x41, 0x8d, 0x80, 0xc3, 0x80, 0x53, 0x88, + 0x80, 0xaa, 0x84, 0xe6, 0x81, 0xdc, 0x82, 0x60, + 0x6f, 0x15, 0x80, 0x45, 0xf5, 0x80, 0x43, 0xc1, + 0x80, 0x95, 0x80, 0x40, 0x88, 0x80, 0xeb, 0x80, + 0x94, 0x81, 0x60, 0x54, 0x7a, 0x80, 0x48, 0x0f, + 0x81, 0x45, 0xca, 0x80, 0x9a, 0x03, 0x80, 0x44, + 0xc6, 0x80, 0x41, 0x24, 0x80, 0xf3, 0x81, 0x41, + 0xf1, 0x82, 0x44, 0xce, 0x80, 0x43, 0x3f, 0x80, + 0x60, 0x4d, 0x67, 0x81, 0x44, 0x9b, 0x08, 0x80, + 0x8d, 0x81, 0x60, 0x71, 0x47, 0x81, 0x44, 0xb0, + 0x80, 0x43, 0x53, 0x82, +}; + +static const uint8_t unicode_prop_Hex_Digit_table[12] = { + 0xaf, 0x89, 0x35, 0x99, 0x85, 0x60, 0xfe, 0xa8, + 0x89, 0x35, 0x99, 0x85, +}; + +static const uint8_t unicode_prop_IDS_Unary_Operator_table[4] = { + 0x60, 0x2f, 0xfd, 0x81, +}; + +static const uint8_t unicode_prop_IDS_Binary_Operator_table[8] = { + 0x60, 0x2f, 0xef, 0x09, 0x89, 0x41, 0xf0, 0x80, +}; + +static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = { + 0x60, 0x2f, 0xf1, 0x81, +}; + +static const uint8_t unicode_prop_Ideographic_table[71] = { + 0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82, + 0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff, + 0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60, + 0x75, 0x09, 0x80, 0x8c, 0x84, 0x88, 0x5c, 0xd5, + 0xa8, 0x9f, 0xe0, 0xf2, 0x60, 0x23, 0x7c, 0x41, + 0x8b, 0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f, + 0x51, 0x1d, 0x81, 0x56, 0x8d, 0x81, 0x5d, 0x30, + 0x8e, 0x42, 0x6d, 0x49, 0xa1, 0x42, 0x1d, 0x45, + 0xe1, 0x53, 0x4a, 0x84, 0x60, 0x21, 0x29, +}; + +static const uint8_t unicode_prop_Join_Control_table[4] = { + 0x60, 0x20, 0x0b, 0x81, +}; + +static const uint8_t unicode_prop_Logical_Order_Exception_table[15] = { + 0x4e, 0x3f, 0x84, 0xfa, 0x84, 0x4a, 0xef, 0x11, + 0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81, +}; + +static const uint8_t unicode_prop_Modifier_Combining_Mark_table[16] = { + 0x46, 0x53, 0x09, 0x80, 0x40, 0x82, 0x05, 0x02, + 0x81, 0x41, 0xe0, 0x08, 0x12, 0x80, 0x9e, 0x80, +}; + +static const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = { + 0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, +}; + +static const uint8_t unicode_prop_Pattern_Syntax_table[58] = { + 0xa0, 0x8e, 0x89, 0x86, 0x99, 0x18, 0x80, 0x99, + 0x83, 0xa1, 0x30, 0x00, 0x08, 0x00, 0x0b, 0x03, + 0x02, 0x80, 0x96, 0x80, 0x9e, 0x80, 0x5f, 0x17, + 0x97, 0x87, 0x8e, 0x81, 0x92, 0x80, 0x89, 0x41, + 0x30, 0x42, 0xcf, 0x40, 0x9f, 0x42, 0x75, 0x9d, + 0x44, 0x6b, 0x41, 0xff, 0xff, 0x41, 0x80, 0x13, + 0x98, 0x8e, 0x80, 0x60, 0xcd, 0x0c, 0x81, 0x41, + 0x04, 0x81, +}; + +static const uint8_t unicode_prop_Pattern_White_Space_table[11] = { + 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x5f, 0x87, + 0x81, 0x97, 0x81, +}; + +static const uint8_t unicode_prop_Quotation_Mark_table[31] = { + 0xa1, 0x03, 0x80, 0x40, 0x82, 0x80, 0x8e, 0x80, + 0x5f, 0x5b, 0x87, 0x98, 0x81, 0x4e, 0x06, 0x80, + 0x41, 0xc8, 0x83, 0x8c, 0x82, 0x60, 0xce, 0x20, + 0x83, 0x40, 0xbc, 0x03, 0x80, 0xd9, 0x81, +}; + +static const uint8_t unicode_prop_Radical_table[9] = { + 0x60, 0x2e, 0x7f, 0x99, 0x80, 0xd8, 0x8b, 0x40, + 0xd5, +}; + +static const uint8_t unicode_prop_Regional_Indicator_table[4] = { + 0x61, 0xf1, 0xe5, 0x99, +}; + +static const uint8_t unicode_prop_Sentence_Terminal_table[213] = { + 0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48, + 0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa, + 0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81, + 0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15, + 0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81, + 0x40, 0x9c, 0x81, 0xac, 0x04, 0x80, 0x41, 0x39, + 0x81, 0x41, 0x61, 0x83, 0x40, 0xa1, 0x81, 0x89, + 0x09, 0x81, 0x9c, 0x82, 0x40, 0xba, 0x81, 0xc0, + 0x81, 0x43, 0xa3, 0x80, 0x96, 0x81, 0x88, 0x82, + 0x4c, 0xae, 0x82, 0x41, 0x31, 0x80, 0x8c, 0x80, + 0x95, 0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb, + 0x80, 0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80, + 0x41, 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, + 0x97, 0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81, + 0x40, 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81, + 0xba, 0x02, 0x81, 0x40, 0xa8, 0x80, 0x8b, 0x80, + 0x8f, 0x80, 0xc0, 0x80, 0x4a, 0xf3, 0x81, 0x44, + 0xfc, 0x84, 0xab, 0x83, 0x40, 0xbc, 0x81, 0xf4, + 0x83, 0xfe, 0x82, 0x40, 0x80, 0x0d, 0x80, 0x8f, + 0x81, 0xd7, 0x08, 0x81, 0xeb, 0x80, 0x41, 0x29, + 0x81, 0xf4, 0x81, 0x41, 0x74, 0x0c, 0x8e, 0xe8, + 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80, + 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41, 0xa3, 0x81, + 0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60, 0x4b, 0x28, + 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, 0x8a, 0x80, + 0x42, 0x28, 0x81, 0x41, 0x27, 0x80, 0x60, 0x4e, + 0x05, 0x80, 0x5d, 0xe7, 0x80, +}; + +static const uint8_t unicode_prop_Soft_Dotted_table[79] = { + 0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80, + 0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f, + 0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2, + 0x80, 0x8c, 0x02, 0x80, 0x40, 0x83, 0x80, 0x40, + 0x9c, 0x80, 0x41, 0xa4, 0x80, 0x40, 0xd5, 0x81, + 0x4b, 0x31, 0x80, 0x61, 0xa7, 0xa4, 0x81, 0xb1, + 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, + 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, + 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0x48, + 0x85, 0x80, 0x41, 0x30, 0x81, 0x99, 0x80, +}; + +static const uint8_t unicode_prop_Terminal_Punctuation_table[264] = { + 0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80, + 0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8, + 0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3, + 0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5, + 0x28, 0x87, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44, + 0xf3, 0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36, + 0x81, 0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb, + 0x82, 0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6, + 0x19, 0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83, + 0x40, 0xa1, 0x81, 0x89, 0x08, 0x82, 0x9c, 0x82, + 0x40, 0xba, 0x84, 0xbd, 0x81, 0x43, 0xa3, 0x80, + 0x96, 0x81, 0x88, 0x82, 0x4c, 0xae, 0x82, 0x41, + 0x31, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a, + 0x81, 0x41, 0xab, 0x81, 0x60, 0x74, 0xfa, 0x81, + 0x41, 0x0c, 0x82, 0x40, 0xe2, 0x84, 0x41, 0x7d, + 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x96, 0x82, + 0x40, 0x92, 0x82, 0xfe, 0x80, 0x8f, 0x81, 0x40, + 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81, 0xb8, + 0x10, 0x83, 0x40, 0xa8, 0x80, 0x89, 0x00, 0x80, + 0x8a, 0x0a, 0x80, 0xc0, 0x01, 0x80, 0x44, 0x39, + 0x80, 0xaf, 0x80, 0x44, 0x85, 0x80, 0x40, 0xc6, + 0x80, 0x41, 0x35, 0x81, 0x40, 0x97, 0x85, 0xc3, + 0x85, 0xd8, 0x83, 0x43, 0xb7, 0x84, 0xab, 0x83, + 0x40, 0xbc, 0x86, 0xef, 0x83, 0xfe, 0x82, 0x40, + 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x84, 0xeb, + 0x80, 0x41, 0x29, 0x81, 0xf4, 0x82, 0x8b, 0x81, + 0x41, 0x65, 0x1a, 0x8e, 0xe8, 0x81, 0x40, 0xf8, + 0x82, 0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81, + 0xd6, 0x0b, 0x81, 0x41, 0x9d, 0x82, 0xac, 0x80, + 0x42, 0x84, 0x81, 0xc9, 0x81, 0x45, 0x2a, 0x84, + 0x60, 0x45, 0xf8, 0x81, 0x40, 0x84, 0x80, 0xc0, + 0x82, 0x89, 0x80, 0x42, 0x28, 0x81, 0x41, 0x26, + 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83, +}; + +static const uint8_t unicode_prop_Unified_Ideograph_table[46] = { + 0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51, + 0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89, + 0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60, + 0xa6, 0xdf, 0x9f, 0x51, 0x1d, 0x81, 0x56, 0x8d, + 0x81, 0x5d, 0x30, 0x8e, 0x42, 0x6d, 0x51, 0xa1, + 0x53, 0x4a, 0x84, 0x60, 0x21, 0x29, +}; + +static const uint8_t unicode_prop_Variation_Selector_table[13] = { + 0x58, 0x0a, 0x10, 0x80, 0x60, 0xe5, 0xef, 0x8f, + 0x6d, 0x02, 0xef, 0x40, 0xef, +}; + +static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = { + 0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80, + 0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e, + 0x7d, 0x83, 0x47, 0x5c, 0x81, 0x49, 0x9b, 0x81, + 0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0, + 0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18, + 0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23, + 0x88, 0x08, 0x00, 0x38, 0x9f, 0x0b, 0x20, 0x88, + 0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81, + 0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d, + 0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d, + 0x41, 0x92, 0x95, 0x0d, 0x80, 0x8d, 0x38, 0x35, + 0x10, 0x1c, 0x01, 0x0c, 0x18, 0x02, 0x09, 0x89, + 0x29, 0x81, 0x8b, 0x92, 0x03, 0x08, 0x00, 0x08, + 0x03, 0x21, 0x2a, 0x97, 0x81, 0x8a, 0x0b, 0x18, + 0x09, 0x0b, 0xaa, 0x0f, 0x80, 0xa7, 0x20, 0x00, + 0x14, 0x22, 0x18, 0x14, 0x00, 0x40, 0xff, 0x80, + 0x42, 0x02, 0x1a, 0x08, 0x81, 0x8d, 0x09, 0x89, + 0xaa, 0x87, 0x41, 0xaa, 0x89, 0x0f, 0x60, 0xce, + 0x3c, 0x2c, 0x81, 0x40, 0xa1, 0x81, 0x91, 0x00, + 0x80, 0x9b, 0x00, 0x80, 0x9c, 0x00, 0x00, 0x08, + 0x81, 0x60, 0xd7, 0x76, 0x80, 0xb8, 0x80, 0xb8, + 0x80, 0xb8, 0x80, 0xb8, 0x80, +}; + +static const uint8_t unicode_prop_Emoji_table[239] = { + 0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f, + 0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95, + 0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81, + 0x8b, 0x80, 0x40, 0xa5, 0x80, 0x98, 0x8a, 0x1a, + 0x40, 0xc6, 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, + 0x88, 0x80, 0xb9, 0x18, 0x84, 0x88, 0x01, 0x01, + 0x09, 0x03, 0x01, 0x00, 0x09, 0x02, 0x02, 0x0f, + 0x14, 0x00, 0x04, 0x8b, 0x8a, 0x09, 0x00, 0x08, + 0x80, 0x91, 0x01, 0x81, 0x91, 0x28, 0x00, 0x0a, + 0x0c, 0x01, 0x0b, 0x81, 0x8a, 0x0c, 0x09, 0x04, + 0x08, 0x00, 0x81, 0x93, 0x0c, 0x28, 0x19, 0x03, + 0x01, 0x01, 0x28, 0x01, 0x00, 0x00, 0x05, 0x02, + 0x05, 0x80, 0x89, 0x81, 0x8e, 0x01, 0x03, 0x00, + 0x03, 0x10, 0x80, 0x8a, 0x81, 0xaf, 0x82, 0x88, + 0x80, 0x8d, 0x80, 0x8d, 0x80, 0x41, 0x73, 0x81, + 0x41, 0xce, 0x82, 0x92, 0x81, 0xb2, 0x03, 0x80, + 0x44, 0xd9, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00, + 0x80, 0x61, 0xbd, 0x69, 0x80, 0x40, 0xc9, 0x80, + 0x40, 0x9f, 0x81, 0x8b, 0x81, 0x8d, 0x01, 0x89, + 0xca, 0x99, 0x01, 0x96, 0x80, 0x93, 0x01, 0x88, + 0x94, 0x81, 0x40, 0xad, 0xa1, 0x81, 0xef, 0x09, + 0x02, 0x81, 0xd2, 0x0a, 0x80, 0x41, 0x06, 0x80, + 0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01, + 0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88, + 0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05, + 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0b, 0x82, + 0x89, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, + 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80, + 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x8a, 0x82, 0xb8, + 0x00, 0x83, 0x8f, 0x81, 0x8b, 0x83, 0x89, +}; + +static const uint8_t unicode_prop_Emoji_Component_table[28] = { + 0xa2, 0x05, 0x04, 0x89, 0x5f, 0xd2, 0x80, 0x40, + 0xd4, 0x80, 0x60, 0xdd, 0x2a, 0x80, 0x60, 0xf3, + 0xd5, 0x99, 0x41, 0xfa, 0x84, 0x45, 0xaf, 0x83, + 0x6c, 0x06, 0x6b, 0xdf, +}; + +static const uint8_t unicode_prop_Emoji_Modifier_table[4] = { + 0x61, 0xf3, 0xfa, 0x84, +}; + +static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = { + 0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f, + 0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01, + 0x82, 0xf4, 0x09, 0x8a, 0x94, 0x92, 0x10, 0x1a, + 0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8, 0x0b, + 0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12, 0x84, + 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80, + 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89, + 0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90, + 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88, +}; + +static const uint8_t unicode_prop_Emoji_Presentation_table[145] = { + 0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01, + 0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b, + 0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90, + 0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03, + 0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00, + 0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d, + 0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61, + 0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd, + 0x01, 0x89, 0xca, 0x99, 0x00, 0x97, 0x80, 0x93, + 0x01, 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0, + 0x8b, 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa, + 0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80, + 0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91, + 0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf, + 0xc5, 0x28, 0x12, 0x0b, 0x13, 0x8a, 0x0e, 0x88, + 0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, + 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x8a, + 0x82, 0xb8, 0x00, 0x83, 0x8f, 0x81, 0x8b, 0x83, + 0x89, +}; + +static const uint8_t unicode_prop_Extended_Pictographic_table[254] = { + 0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b, + 0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85, + 0x8e, 0x81, 0x41, 0x6e, 0x81, 0x8b, 0x80, 0x40, + 0xa5, 0x80, 0x98, 0x8a, 0x1a, 0x40, 0xc6, 0x80, + 0x40, 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80, 0xb9, + 0x18, 0x84, 0x88, 0x01, 0x01, 0x09, 0x03, 0x01, + 0x00, 0x09, 0x02, 0x02, 0x0f, 0x14, 0x00, 0x04, + 0x8b, 0x8a, 0x09, 0x00, 0x08, 0x80, 0x91, 0x01, + 0x81, 0x91, 0x28, 0x00, 0x0a, 0x0c, 0x01, 0x0b, + 0x81, 0x8a, 0x0c, 0x09, 0x04, 0x08, 0x00, 0x81, + 0x93, 0x0c, 0x28, 0x19, 0x03, 0x01, 0x01, 0x28, + 0x01, 0x00, 0x00, 0x05, 0x02, 0x05, 0x80, 0x89, + 0x81, 0x8e, 0x01, 0x03, 0x00, 0x03, 0x10, 0x80, + 0x8a, 0x81, 0xaf, 0x82, 0x88, 0x80, 0x8d, 0x80, + 0x8d, 0x80, 0x41, 0x73, 0x81, 0x41, 0xce, 0x82, + 0x92, 0x81, 0xb2, 0x03, 0x80, 0x44, 0xd9, 0x80, + 0x8b, 0x80, 0x42, 0x58, 0x00, 0x80, 0x61, 0xbd, + 0x69, 0x80, 0xa6, 0x83, 0xe3, 0x8b, 0x8e, 0x81, + 0x8e, 0x80, 0x8d, 0x81, 0xa4, 0x89, 0xef, 0x81, + 0x8b, 0x81, 0x8d, 0x01, 0x89, 0x92, 0xb7, 0x9a, + 0x8e, 0x89, 0x80, 0x93, 0x01, 0x88, 0x03, 0x88, + 0x96, 0x85, 0x40, 0xbb, 0x81, 0xef, 0x09, 0x02, + 0x81, 0xd2, 0x0a, 0x03, 0x84, 0x40, 0xfd, 0x80, + 0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01, + 0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88, + 0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05, + 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x81, 0x90, + 0x10, 0x05, 0x81, 0x8c, 0x40, 0xd9, 0xa5, 0x8b, + 0x83, 0xb7, 0x87, 0x89, 0x85, 0xa7, 0x87, 0x9d, + 0x81, 0x8b, 0x19, 0x8d, 0x88, 0xa6, 0x8b, 0xae, + 0x80, 0x89, 0x80, 0x40, 0xb8, 0xd7, 0x87, 0x8d, + 0x40, 0x91, 0x40, 0xff, 0x43, 0xfd, +}; + +static const uint8_t unicode_prop_Default_Ignorable_Code_Point_table[51] = { + 0x40, 0xac, 0x80, 0x42, 0xa0, 0x80, 0x42, 0xcb, + 0x80, 0x4b, 0x41, 0x81, 0x46, 0x52, 0x81, 0xd4, + 0x84, 0x47, 0xfa, 0x84, 0x99, 0x84, 0xb0, 0x8f, + 0x50, 0xf3, 0x80, 0x60, 0xcc, 0x9a, 0x8f, 0x40, + 0xee, 0x80, 0x40, 0x9f, 0x80, 0xce, 0x88, 0x60, + 0xbc, 0xa6, 0x83, 0x54, 0xce, 0x87, 0x6c, 0x2e, + 0x84, 0x4f, 0xff, +}; + +typedef enum { + UNICODE_PROP_Hyphen, + UNICODE_PROP_Other_Math, + UNICODE_PROP_Other_Alphabetic, + UNICODE_PROP_Other_Lowercase, + UNICODE_PROP_Other_Uppercase, + UNICODE_PROP_Other_Grapheme_Extend, + UNICODE_PROP_Other_Default_Ignorable_Code_Point, + UNICODE_PROP_Other_ID_Start, + UNICODE_PROP_Other_ID_Continue, + UNICODE_PROP_Prepended_Concatenation_Mark, + UNICODE_PROP_ID_Continue1, + UNICODE_PROP_XID_Start1, + UNICODE_PROP_XID_Continue1, + UNICODE_PROP_Changes_When_Titlecased1, + UNICODE_PROP_Changes_When_Casefolded1, + UNICODE_PROP_Changes_When_NFKC_Casefolded1, + UNICODE_PROP_ASCII_Hex_Digit, + UNICODE_PROP_Bidi_Control, + UNICODE_PROP_Dash, + UNICODE_PROP_Deprecated, + UNICODE_PROP_Diacritic, + UNICODE_PROP_Extender, + UNICODE_PROP_Hex_Digit, + UNICODE_PROP_IDS_Unary_Operator, + UNICODE_PROP_IDS_Binary_Operator, + UNICODE_PROP_IDS_Trinary_Operator, + UNICODE_PROP_Ideographic, + UNICODE_PROP_Join_Control, + UNICODE_PROP_Logical_Order_Exception, + UNICODE_PROP_Modifier_Combining_Mark, + UNICODE_PROP_Noncharacter_Code_Point, + UNICODE_PROP_Pattern_Syntax, + UNICODE_PROP_Pattern_White_Space, + UNICODE_PROP_Quotation_Mark, + UNICODE_PROP_Radical, + UNICODE_PROP_Regional_Indicator, + UNICODE_PROP_Sentence_Terminal, + UNICODE_PROP_Soft_Dotted, + UNICODE_PROP_Terminal_Punctuation, + UNICODE_PROP_Unified_Ideograph, + UNICODE_PROP_Variation_Selector, + UNICODE_PROP_White_Space, + UNICODE_PROP_Bidi_Mirrored, + UNICODE_PROP_Emoji, + UNICODE_PROP_Emoji_Component, + UNICODE_PROP_Emoji_Modifier, + UNICODE_PROP_Emoji_Modifier_Base, + UNICODE_PROP_Emoji_Presentation, + UNICODE_PROP_Extended_Pictographic, + UNICODE_PROP_Default_Ignorable_Code_Point, + UNICODE_PROP_ID_Start, + UNICODE_PROP_Case_Ignorable, + UNICODE_PROP_ASCII, + UNICODE_PROP_Alphabetic, + UNICODE_PROP_Any, + UNICODE_PROP_Assigned, + UNICODE_PROP_Cased, + UNICODE_PROP_Changes_When_Casefolded, + UNICODE_PROP_Changes_When_Casemapped, + UNICODE_PROP_Changes_When_Lowercased, + UNICODE_PROP_Changes_When_NFKC_Casefolded, + UNICODE_PROP_Changes_When_Titlecased, + UNICODE_PROP_Changes_When_Uppercased, + UNICODE_PROP_Grapheme_Base, + UNICODE_PROP_Grapheme_Extend, + UNICODE_PROP_ID_Continue, + UNICODE_PROP_ID_Compat_Math_Start, + UNICODE_PROP_ID_Compat_Math_Continue, + UNICODE_PROP_Lowercase, + UNICODE_PROP_Math, + UNICODE_PROP_Uppercase, + UNICODE_PROP_XID_Continue, + UNICODE_PROP_XID_Start, + UNICODE_PROP_Cased1, + UNICODE_PROP_InCB, + UNICODE_PROP_COUNT, +} UnicodePropertyEnum; + +static const char unicode_prop_name_table[] = + "ASCII_Hex_Digit,AHex" "\0" + "Bidi_Control,Bidi_C" "\0" + "Dash" "\0" + "Deprecated,Dep" "\0" + "Diacritic,Dia" "\0" + "Extender,Ext" "\0" + "Hex_Digit,Hex" "\0" + "IDS_Unary_Operator,IDSU" "\0" + "IDS_Binary_Operator,IDSB" "\0" + "IDS_Trinary_Operator,IDST" "\0" + "Ideographic,Ideo" "\0" + "Join_Control,Join_C" "\0" + "Logical_Order_Exception,LOE" "\0" + "Modifier_Combining_Mark,MCM" "\0" + "Noncharacter_Code_Point,NChar" "\0" + "Pattern_Syntax,Pat_Syn" "\0" + "Pattern_White_Space,Pat_WS" "\0" + "Quotation_Mark,QMark" "\0" + "Radical" "\0" + "Regional_Indicator,RI" "\0" + "Sentence_Terminal,STerm" "\0" + "Soft_Dotted,SD" "\0" + "Terminal_Punctuation,Term" "\0" + "Unified_Ideograph,UIdeo" "\0" + "Variation_Selector,VS" "\0" + "White_Space,space" "\0" + "Bidi_Mirrored,Bidi_M" "\0" + "Emoji" "\0" + "Emoji_Component,EComp" "\0" + "Emoji_Modifier,EMod" "\0" + "Emoji_Modifier_Base,EBase" "\0" + "Emoji_Presentation,EPres" "\0" + "Extended_Pictographic,ExtPict" "\0" + "Default_Ignorable_Code_Point,DI" "\0" + "ID_Start,IDS" "\0" + "Case_Ignorable,CI" "\0" + "ASCII" "\0" + "Alphabetic,Alpha" "\0" + "Any" "\0" + "Assigned" "\0" + "Cased" "\0" + "Changes_When_Casefolded,CWCF" "\0" + "Changes_When_Casemapped,CWCM" "\0" + "Changes_When_Lowercased,CWL" "\0" + "Changes_When_NFKC_Casefolded,CWKCF" "\0" + "Changes_When_Titlecased,CWT" "\0" + "Changes_When_Uppercased,CWU" "\0" + "Grapheme_Base,Gr_Base" "\0" + "Grapheme_Extend,Gr_Ext" "\0" + "ID_Continue,IDC" "\0" + "ID_Compat_Math_Start" "\0" + "ID_Compat_Math_Continue" "\0" + "Lowercase,Lower" "\0" + "Math" "\0" + "Uppercase,Upper" "\0" + "XID_Continue,XIDC" "\0" + "XID_Start,XIDS" "\0" +; + +static const uint8_t * const unicode_prop_table[] = { + unicode_prop_Hyphen_table, + unicode_prop_Other_Math_table, + unicode_prop_Other_Alphabetic_table, + unicode_prop_Other_Lowercase_table, + unicode_prop_Other_Uppercase_table, + unicode_prop_Other_Grapheme_Extend_table, + unicode_prop_Other_Default_Ignorable_Code_Point_table, + unicode_prop_Other_ID_Start_table, + unicode_prop_Other_ID_Continue_table, + unicode_prop_Prepended_Concatenation_Mark_table, + unicode_prop_ID_Continue1_table, + unicode_prop_XID_Start1_table, + unicode_prop_XID_Continue1_table, + unicode_prop_Changes_When_Titlecased1_table, + unicode_prop_Changes_When_Casefolded1_table, + unicode_prop_Changes_When_NFKC_Casefolded1_table, + unicode_prop_ASCII_Hex_Digit_table, + unicode_prop_Bidi_Control_table, + unicode_prop_Dash_table, + unicode_prop_Deprecated_table, + unicode_prop_Diacritic_table, + unicode_prop_Extender_table, + unicode_prop_Hex_Digit_table, + unicode_prop_IDS_Unary_Operator_table, + unicode_prop_IDS_Binary_Operator_table, + unicode_prop_IDS_Trinary_Operator_table, + unicode_prop_Ideographic_table, + unicode_prop_Join_Control_table, + unicode_prop_Logical_Order_Exception_table, + unicode_prop_Modifier_Combining_Mark_table, + unicode_prop_Noncharacter_Code_Point_table, + unicode_prop_Pattern_Syntax_table, + unicode_prop_Pattern_White_Space_table, + unicode_prop_Quotation_Mark_table, + unicode_prop_Radical_table, + unicode_prop_Regional_Indicator_table, + unicode_prop_Sentence_Terminal_table, + unicode_prop_Soft_Dotted_table, + unicode_prop_Terminal_Punctuation_table, + unicode_prop_Unified_Ideograph_table, + unicode_prop_Variation_Selector_table, + unicode_prop_White_Space_table, + unicode_prop_Bidi_Mirrored_table, + unicode_prop_Emoji_table, + unicode_prop_Emoji_Component_table, + unicode_prop_Emoji_Modifier_table, + unicode_prop_Emoji_Modifier_Base_table, + unicode_prop_Emoji_Presentation_table, + unicode_prop_Extended_Pictographic_table, + unicode_prop_Default_Ignorable_Code_Point_table, + unicode_prop_ID_Start_table, + unicode_prop_Case_Ignorable_table, +}; + +static const uint16_t unicode_prop_len_table[] = { + countof(unicode_prop_Hyphen_table), + countof(unicode_prop_Other_Math_table), + countof(unicode_prop_Other_Alphabetic_table), + countof(unicode_prop_Other_Lowercase_table), + countof(unicode_prop_Other_Uppercase_table), + countof(unicode_prop_Other_Grapheme_Extend_table), + countof(unicode_prop_Other_Default_Ignorable_Code_Point_table), + countof(unicode_prop_Other_ID_Start_table), + countof(unicode_prop_Other_ID_Continue_table), + countof(unicode_prop_Prepended_Concatenation_Mark_table), + countof(unicode_prop_ID_Continue1_table), + countof(unicode_prop_XID_Start1_table), + countof(unicode_prop_XID_Continue1_table), + countof(unicode_prop_Changes_When_Titlecased1_table), + countof(unicode_prop_Changes_When_Casefolded1_table), + countof(unicode_prop_Changes_When_NFKC_Casefolded1_table), + countof(unicode_prop_ASCII_Hex_Digit_table), + countof(unicode_prop_Bidi_Control_table), + countof(unicode_prop_Dash_table), + countof(unicode_prop_Deprecated_table), + countof(unicode_prop_Diacritic_table), + countof(unicode_prop_Extender_table), + countof(unicode_prop_Hex_Digit_table), + countof(unicode_prop_IDS_Unary_Operator_table), + countof(unicode_prop_IDS_Binary_Operator_table), + countof(unicode_prop_IDS_Trinary_Operator_table), + countof(unicode_prop_Ideographic_table), + countof(unicode_prop_Join_Control_table), + countof(unicode_prop_Logical_Order_Exception_table), + countof(unicode_prop_Modifier_Combining_Mark_table), + countof(unicode_prop_Noncharacter_Code_Point_table), + countof(unicode_prop_Pattern_Syntax_table), + countof(unicode_prop_Pattern_White_Space_table), + countof(unicode_prop_Quotation_Mark_table), + countof(unicode_prop_Radical_table), + countof(unicode_prop_Regional_Indicator_table), + countof(unicode_prop_Sentence_Terminal_table), + countof(unicode_prop_Soft_Dotted_table), + countof(unicode_prop_Terminal_Punctuation_table), + countof(unicode_prop_Unified_Ideograph_table), + countof(unicode_prop_Variation_Selector_table), + countof(unicode_prop_White_Space_table), + countof(unicode_prop_Bidi_Mirrored_table), + countof(unicode_prop_Emoji_table), + countof(unicode_prop_Emoji_Component_table), + countof(unicode_prop_Emoji_Modifier_table), + countof(unicode_prop_Emoji_Modifier_Base_table), + countof(unicode_prop_Emoji_Presentation_table), + countof(unicode_prop_Extended_Pictographic_table), + countof(unicode_prop_Default_Ignorable_Code_Point_table), + countof(unicode_prop_ID_Start_table), + countof(unicode_prop_Case_Ignorable_table), +}; + diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/libunicode.c b/host/cred-script/vendor/rquickjs-sys/quickjs/libunicode.c new file mode 100644 index 0000000..a621c52 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/libunicode.c @@ -0,0 +1,1746 @@ +/* + * Unicode utilities + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include + +#include "cutils.h" +#include "libunicode.h" +#include "libunicode-table.h" + +// note: stored as 4 bit tag, not much room left +enum { + RUN_TYPE_U, + RUN_TYPE_L, + RUN_TYPE_UF, + RUN_TYPE_LF, + RUN_TYPE_UL, + RUN_TYPE_LSU, + RUN_TYPE_U2L_399_EXT2, + RUN_TYPE_UF_D20, + RUN_TYPE_UF_D1_EXT, + RUN_TYPE_U_EXT, + RUN_TYPE_LF_EXT, + RUN_TYPE_UF_EXT2, + RUN_TYPE_LF_EXT2, + RUN_TYPE_UF_EXT3, +}; + +static int lre_case_conv1(uint32_t c, int conv_type) +{ + uint32_t res[LRE_CC_RES_LEN_MAX]; + lre_case_conv(res, c, conv_type); + return res[0]; +} + +/* case conversion using the table entry 'idx' with value 'v' */ +static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v) +{ + uint32_t code, data, type, a, is_lower; + is_lower = (conv_type != 0); + type = (v >> (32 - 17 - 7 - 4)) & 0xf; + data = ((v & 0xf) << 8) | case_conv_table2[idx]; + code = v >> (32 - 17); + switch(type) { + case RUN_TYPE_U: + case RUN_TYPE_L: + case RUN_TYPE_UF: + case RUN_TYPE_LF: + if (conv_type == (type & 1) || + (type >= RUN_TYPE_UF && conv_type == 2)) { + c = c - code + (case_conv_table1[data] >> (32 - 17)); + } + break; + case RUN_TYPE_UL: + a = c - code; + if ((a & 1) != (1 - is_lower)) + break; + c = (a ^ 1) + code; + break; + case RUN_TYPE_LSU: + a = c - code; + if (a == 1) { + c += 2 * is_lower - 1; + } else if (a == (1 - is_lower) * 2) { + c += (2 * is_lower - 1) * 2; + } + break; + case RUN_TYPE_U2L_399_EXT2: + if (!is_lower) { + res[0] = c - code + case_conv_ext[data >> 6]; + res[1] = 0x399; + return 2; + } else { + c = c - code + case_conv_ext[data & 0x3f]; + } + break; + case RUN_TYPE_UF_D20: + if (conv_type == 1) + break; + c = data + (conv_type == 2) * 0x20; + break; + case RUN_TYPE_UF_D1_EXT: + if (conv_type == 1) + break; + c = case_conv_ext[data] + (conv_type == 2); + break; + case RUN_TYPE_U_EXT: + case RUN_TYPE_LF_EXT: + if (is_lower != (type - RUN_TYPE_U_EXT)) + break; + c = case_conv_ext[data]; + break; + case RUN_TYPE_LF_EXT2: + if (!is_lower) + break; + res[0] = c - code + case_conv_ext[data >> 6]; + res[1] = case_conv_ext[data & 0x3f]; + return 2; + case RUN_TYPE_UF_EXT2: + if (conv_type == 1) + break; + res[0] = c - code + case_conv_ext[data >> 6]; + res[1] = case_conv_ext[data & 0x3f]; + if (conv_type == 2) { + /* convert to lower */ + res[0] = lre_case_conv1(res[0], 1); + res[1] = lre_case_conv1(res[1], 1); + } + return 2; + default: + case RUN_TYPE_UF_EXT3: + if (conv_type == 1) + break; + res[0] = case_conv_ext[data >> 8]; + res[1] = case_conv_ext[(data >> 4) & 0xf]; + res[2] = case_conv_ext[data & 0xf]; + if (conv_type == 2) { + /* convert to lower */ + res[0] = lre_case_conv1(res[0], 1); + res[1] = lre_case_conv1(res[1], 1); + res[2] = lre_case_conv1(res[2], 1); + } + return 3; + } + res[0] = c; + return 1; +} + +/* conv_type: + 0 = to upper + 1 = to lower + 2 = case folding (= to lower with modifications) +*/ +int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) +{ + if (c < 128) { + if (conv_type) { + if (c >= 'A' && c <= 'Z') { + c = c - 'A' + 'a'; + } + } else { + if (c >= 'a' && c <= 'z') { + c = c - 'a' + 'A'; + } + } + } else { + uint32_t v, code, len; + int idx, idx_min, idx_max; + + idx_min = 0; + idx_max = countof(case_conv_table1) - 1; + while (idx_min <= idx_max) { + idx = (unsigned)(idx_max + idx_min) / 2; + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + if (c < code) { + idx_max = idx - 1; + } else if (c >= code + len) { + idx_min = idx + 1; + } else { + return lre_case_conv_entry(res, c, conv_type, idx, v); + } + } + } + res[0] = c; + return 1; +} + +static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, bool is_unicode) +{ + uint32_t res[LRE_CC_RES_LEN_MAX]; + int len; + + if (is_unicode) { + len = lre_case_conv_entry(res, c, 2, idx, v); + if (len == 1) { + c = res[0]; + } else { + /* handle the few specific multi-character cases (see + unicode_gen.c:dump_case_folding_special_cases()) */ + if (c == 0xfb06) { + c = 0xfb05; + } else if (c == 0x01fd3) { + c = 0x390; + } else if (c == 0x01fe3) { + c = 0x3b0; + } + } + } else { + if (likely(c < 128)) { + if (c >= 'a' && c <= 'z') + c = c - 'a' + 'A'; + } else { + /* legacy regexp: to upper case if single char >= 128 */ + len = lre_case_conv_entry(res, c, false, idx, v); + if (len == 1 && res[0] >= 128) + c = res[0]; + } + } + return c; +} + +/* JS regexp specific rules for case folding */ +int lre_canonicalize(uint32_t c, bool is_unicode) +{ + if (c < 128) { + /* fast case */ + if (is_unicode) { + if (c >= 'A' && c <= 'Z') { + c = c - 'A' + 'a'; + } + } else { + if (c >= 'a' && c <= 'z') { + c = c - 'a' + 'A'; + } + } + } else { + uint32_t v, code, len; + int idx, idx_min, idx_max; + + idx_min = 0; + idx_max = countof(case_conv_table1) - 1; + while (idx_min <= idx_max) { + idx = (unsigned)(idx_max + idx_min) / 2; + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + if (c < code) { + idx_max = idx - 1; + } else if (c >= code + len) { + idx_min = idx + 1; + } else { + return lre_case_folding_entry(c, idx, v, is_unicode); + } + } + } + return c; +} + +static uint32_t get_le24(const uint8_t *ptr) +{ + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16); +} + +#define UNICODE_INDEX_BLOCK_LEN 32 + +/* return -1 if not in table, otherwise the offset in the block */ +static int get_index_pos(uint32_t *pcode, uint32_t c, + const uint8_t *index_table, int index_table_len) +{ + uint32_t code, v; + int idx_min, idx_max, idx; + + idx_min = 0; + v = get_le24(index_table); + code = v & ((1 << 21) - 1); + if (c < code) { + *pcode = 0; + return 0; + } + idx_max = index_table_len - 1; + code = get_le24(index_table + idx_max * 3); + if (c >= code) + return -1; + /* invariant: tab[idx_min] <= c < tab2[idx_max] */ + while ((idx_max - idx_min) > 1) { + idx = (idx_max + idx_min) / 2; + v = get_le24(index_table + idx * 3); + code = v & ((1 << 21) - 1); + if (c < code) { + idx_max = idx; + } else { + idx_min = idx; + } + } + v = get_le24(index_table + idx_min * 3); + *pcode = v & ((1 << 21) - 1); + return (idx_min + 1) * UNICODE_INDEX_BLOCK_LEN + (v >> 21); +} + +static bool lre_is_in_table(uint32_t c, const uint8_t *table, + const uint8_t *index_table, int index_table_len) +{ + uint32_t code, b, bit; + int pos; + const uint8_t *p; + + pos = get_index_pos(&code, c, index_table, index_table_len); + if (pos < 0) + return false; /* outside the table */ + p = table + pos; + bit = 0; + for(;;) { + b = *p++; + if (b < 64) { + code += (b >> 3) + 1; + if (c < code) + return bit; + bit ^= 1; + code += (b & 7) + 1; + } else if (b >= 0x80) { + code += b - 0x80 + 1; + } else if (b < 0x60) { + code += (((b - 0x40) << 8) | p[0]) + 1; + p++; + } else { + code += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1; + p += 2; + } + if (c < code) + return bit; + bit ^= 1; + } +} + +bool lre_is_cased(uint32_t c) +{ + uint32_t v, code, len; + int idx, idx_min, idx_max; + + idx_min = 0; + idx_max = countof(case_conv_table1) - 1; + while (idx_min <= idx_max) { + idx = (unsigned)(idx_max + idx_min) / 2; + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + if (c < code) { + idx_max = idx - 1; + } else if (c >= code + len) { + idx_min = idx + 1; + } else { + return true; + } + } + return lre_is_in_table(c, unicode_prop_Cased1_table, + unicode_prop_Cased1_index, + sizeof(unicode_prop_Cased1_index) / 3); +} + +bool lre_is_case_ignorable(uint32_t c) +{ + return lre_is_in_table(c, unicode_prop_Case_Ignorable_table, + unicode_prop_Case_Ignorable_index, + sizeof(unicode_prop_Case_Ignorable_index) / 3); +} + +/* character range */ + +static __maybe_unused void cr_dump(CharRange *cr) +{ + int i; + for(i = 0; i < cr->len; i++) + printf("%d: 0x%04x\n", i, cr->points[i]); +} + +static void *cr_default_realloc(void *opaque, void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +void cr_init(CharRange *cr, void *mem_opaque, DynBufReallocFunc *realloc_func) +{ + cr->len = cr->size = 0; + cr->points = NULL; + cr->mem_opaque = mem_opaque; + cr->realloc_func = realloc_func ? realloc_func : cr_default_realloc; +} + +void cr_free(CharRange *cr) +{ + cr->realloc_func(cr->mem_opaque, cr->points, 0); +} + +int cr_realloc(CharRange *cr, int size) +{ + int new_size; + uint32_t *new_buf; + + if (size > cr->size) { + new_size = max_int(size, cr->size * 3 / 2); + new_buf = cr->realloc_func(cr->mem_opaque, cr->points, + new_size * sizeof(cr->points[0])); + if (!new_buf) + return -1; + cr->points = new_buf; + cr->size = new_size; + } + return 0; +} + +int cr_copy(CharRange *cr, const CharRange *cr1) +{ + if (cr_realloc(cr, cr1->len)) + return -1; + memcpy(cr->points, cr1->points, sizeof(cr->points[0]) * cr1->len); + cr->len = cr1->len; + return 0; +} + +/* merge consecutive intervals and remove empty intervals */ +static void cr_compress(CharRange *cr) +{ + int i, j, k, len; + uint32_t *pt; + + pt = cr->points; + len = cr->len; + i = 0; + j = 0; + k = 0; + while ((i + 1) < len) { + if (pt[i] == pt[i + 1]) { + /* empty interval */ + i += 2; + } else { + j = i; + while ((j + 3) < len && pt[j + 1] == pt[j + 2]) + j += 2; + /* just copy */ + pt[k] = pt[i]; + pt[k + 1] = pt[j + 1]; + k += 2; + i = j + 2; + } + } + cr->len = k; +} + +/* union or intersection */ +int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, + const uint32_t *b_pt, int b_len, int op) +{ + int a_idx, b_idx, is_in; + uint32_t v; + + a_idx = 0; + b_idx = 0; + for(;;) { + /* get one more point from a or b in increasing order */ + if (a_idx < a_len && b_idx < b_len) { + if (a_pt[a_idx] < b_pt[b_idx]) { + goto a_add; + } else if (a_pt[a_idx] == b_pt[b_idx]) { + v = a_pt[a_idx]; + a_idx++; + b_idx++; + } else { + goto b_add; + } + } else if (a_idx < a_len) { + a_add: + v = a_pt[a_idx++]; + } else if (b_idx < b_len) { + b_add: + v = b_pt[b_idx++]; + } else { + break; + } + /* add the point if the in/out status changes */ + switch(op) { + case CR_OP_UNION: + is_in = (a_idx & 1) | (b_idx & 1); + break; + case CR_OP_INTER: + is_in = (a_idx & 1) & (b_idx & 1); + break; + case CR_OP_XOR: + is_in = (a_idx & 1) ^ (b_idx & 1); + break; + default: + abort(); + } + if (is_in != (cr->len & 1)) { + if (cr_add_point(cr, v)) + return -1; + } + } + cr_compress(cr); + return 0; +} + +int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len) +{ + CharRange a = *cr; + int ret; + cr->len = 0; + cr->size = 0; + cr->points = NULL; + ret = cr_op(cr, a.points, a.len, b_pt, b_len, CR_OP_UNION); + cr_free(&a); + return ret; +} + +int cr_invert(CharRange *cr) +{ + int len; + len = cr->len; + if (cr_realloc(cr, len + 2)) + return -1; + memmove(cr->points + 1, cr->points, len * sizeof(cr->points[0])); + cr->points[0] = 0; + cr->points[len + 1] = UINT32_MAX; + cr->len = len + 2; + cr_compress(cr); + return 0; +} + +bool lre_is_id_start(uint32_t c) +{ + return lre_is_in_table(c, unicode_prop_ID_Start_table, + unicode_prop_ID_Start_index, + sizeof(unicode_prop_ID_Start_index) / 3); +} + +bool lre_is_id_continue(uint32_t c) +{ + return lre_is_id_start(c) || + lre_is_in_table(c, unicode_prop_ID_Continue1_table, + unicode_prop_ID_Continue1_index, + sizeof(unicode_prop_ID_Continue1_index) / 3); +} + +bool lre_is_white_space(uint32_t c) +{ + return lre_is_in_table(c, unicode_prop_White_Space_table, + unicode_prop_White_Space_index, + sizeof(unicode_prop_White_Space_index) / 3); +} + +#define UNICODE_DECOMP_LEN_MAX 18 + +typedef enum { + DECOMP_TYPE_C1, /* 16 bit char */ + DECOMP_TYPE_L1, /* 16 bit char table */ + DECOMP_TYPE_L2, + DECOMP_TYPE_L3, + DECOMP_TYPE_L4, + DECOMP_TYPE_L5, /* XXX: not used */ + DECOMP_TYPE_L6, /* XXX: could remove */ + DECOMP_TYPE_L7, /* XXX: could remove */ + DECOMP_TYPE_LL1, /* 18 bit char table */ + DECOMP_TYPE_LL2, + DECOMP_TYPE_S1, /* 8 bit char table */ + DECOMP_TYPE_S2, + DECOMP_TYPE_S3, + DECOMP_TYPE_S4, + DECOMP_TYPE_S5, + DECOMP_TYPE_I1, /* increment 16 bit char value */ + DECOMP_TYPE_I2_0, + DECOMP_TYPE_I2_1, + DECOMP_TYPE_I3_1, + DECOMP_TYPE_I3_2, + DECOMP_TYPE_I4_1, + DECOMP_TYPE_I4_2, + DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */ + DECOMP_TYPE_B2, + DECOMP_TYPE_B3, + DECOMP_TYPE_B4, + DECOMP_TYPE_B5, + DECOMP_TYPE_B6, + DECOMP_TYPE_B7, + DECOMP_TYPE_B8, + DECOMP_TYPE_B18, + DECOMP_TYPE_LS2, + DECOMP_TYPE_PAT3, + DECOMP_TYPE_S2_UL, + DECOMP_TYPE_LS2_UL, +} DecompTypeEnum; + +static uint32_t unicode_get_short_code(uint32_t c) +{ + static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 }; + + if (c < 0x80) + return c; + else if (c < 0x80 + 0x50) + return c - 0x80 + 0x300; + else + return unicode_short_table[c - 0x80 - 0x50]; +} + +static uint32_t unicode_get_lower_simple(uint32_t c) +{ + if (c < 0x100 || (c >= 0x410 && c <= 0x42f)) + c += 0x20; + else + c++; + return c; +} + +static uint16_t unicode_get16(const uint8_t *p) +{ + return p[0] | (p[1] << 8); +} + +static int unicode_decomp_entry(uint32_t *res, uint32_t c, + int idx, uint32_t code, uint32_t len, + uint32_t type) +{ + uint32_t c1; + int l, i, p; + const uint8_t *d; + + if (type == DECOMP_TYPE_C1) { + res[0] = unicode_decomp_table2[idx]; + return 1; + } else { + d = unicode_decomp_data + unicode_decomp_table2[idx]; + switch(type) { + case DECOMP_TYPE_L1: + case DECOMP_TYPE_L2: + case DECOMP_TYPE_L3: + case DECOMP_TYPE_L4: + case DECOMP_TYPE_L5: + case DECOMP_TYPE_L6: + case DECOMP_TYPE_L7: + l = type - DECOMP_TYPE_L1 + 1; + d += (c - code) * l * 2; + for(i = 0; i < l; i++) { + if ((res[i] = unicode_get16(d + 2 * i)) == 0) + return 0; + } + return l; + case DECOMP_TYPE_LL1: + case DECOMP_TYPE_LL2: + { + uint32_t k, p; + l = type - DECOMP_TYPE_LL1 + 1; + k = (c - code) * l; + p = len * l * 2; + for(i = 0; i < l; i++) { + c1 = unicode_get16(d + 2 * k) | + (((d[p + (k / 4)] >> ((k % 4) * 2)) & 3) << 16); + if (!c1) + return 0; + res[i] = c1; + k++; + } + } + return l; + case DECOMP_TYPE_S1: + case DECOMP_TYPE_S2: + case DECOMP_TYPE_S3: + case DECOMP_TYPE_S4: + case DECOMP_TYPE_S5: + l = type - DECOMP_TYPE_S1 + 1; + d += (c - code) * l; + for(i = 0; i < l; i++) { + if ((res[i] = unicode_get_short_code(d[i])) == 0) + return 0; + } + return l; + case DECOMP_TYPE_I1: + l = 1; + p = 0; + goto decomp_type_i; + case DECOMP_TYPE_I2_0: + case DECOMP_TYPE_I2_1: + case DECOMP_TYPE_I3_1: + case DECOMP_TYPE_I3_2: + case DECOMP_TYPE_I4_1: + case DECOMP_TYPE_I4_2: + l = 2 + ((type - DECOMP_TYPE_I2_0) >> 1); + p = ((type - DECOMP_TYPE_I2_0) & 1) + (l > 2); + decomp_type_i: + for(i = 0; i < l; i++) { + c1 = unicode_get16(d + 2 * i); + if (i == p) + c1 += c - code; + res[i] = c1; + } + return l; + case DECOMP_TYPE_B18: + l = 18; + goto decomp_type_b; + case DECOMP_TYPE_B1: + case DECOMP_TYPE_B2: + case DECOMP_TYPE_B3: + case DECOMP_TYPE_B4: + case DECOMP_TYPE_B5: + case DECOMP_TYPE_B6: + case DECOMP_TYPE_B7: + case DECOMP_TYPE_B8: + l = type - DECOMP_TYPE_B1 + 1; + decomp_type_b: + { + uint32_t c_min; + c_min = unicode_get16(d); + d += 2 + (c - code) * l; + for(i = 0; i < l; i++) { + c1 = d[i]; + if (c1 == 0xff) + c1 = 0x20; + else + c1 += c_min; + res[i] = c1; + } + } + return l; + case DECOMP_TYPE_LS2: + d += (c - code) * 3; + if (!(res[0] = unicode_get16(d))) + return 0; + res[1] = unicode_get_short_code(d[2]); + return 2; + case DECOMP_TYPE_PAT3: + res[0] = unicode_get16(d); + res[2] = unicode_get16(d + 2); + d += 4 + (c - code) * 2; + res[1] = unicode_get16(d); + return 3; + case DECOMP_TYPE_S2_UL: + case DECOMP_TYPE_LS2_UL: + c1 = c - code; + if (type == DECOMP_TYPE_S2_UL) { + d += c1 & ~1; + c = unicode_get_short_code(*d); + d++; + } else { + d += (c1 >> 1) * 3; + c = unicode_get16(d); + d += 2; + } + if (c1 & 1) + c = unicode_get_lower_simple(c); + res[0] = c; + res[1] = unicode_get_short_code(*d); + return 2; + } + } + return 0; +} + + +/* return the length of the decomposition (length <= + UNICODE_DECOMP_LEN_MAX) or 0 if no decomposition */ +static int unicode_decomp_char(uint32_t *res, uint32_t c, bool is_compat1) +{ + uint32_t v, type, is_compat, code, len; + int idx_min, idx_max, idx; + + idx_min = 0; + idx_max = countof(unicode_decomp_table1) - 1; + while (idx_min <= idx_max) { + idx = (idx_max + idx_min) / 2; + v = unicode_decomp_table1[idx]; + code = v >> (32 - 18); + len = (v >> (32 - 18 - 7)) & 0x7f; + // printf("idx=%d code=%05x len=%d\n", idx, code, len); + if (c < code) { + idx_max = idx - 1; + } else if (c >= code + len) { + idx_min = idx + 1; + } else { + is_compat = v & 1; + if (is_compat1 < is_compat) + break; + type = (v >> (32 - 18 - 7 - 6)) & 0x3f; + return unicode_decomp_entry(res, c, idx, code, len, type); + } + } + return 0; +} + +/* return 0 if no pair found */ +static int unicode_compose_pair(uint32_t c0, uint32_t c1) +{ + uint32_t code, len, type, v, idx1, d_idx, d_offset, ch; + int idx_min, idx_max, idx, d; + uint32_t pair[2]; + + idx_min = 0; + idx_max = countof(unicode_comp_table) - 1; + while (idx_min <= idx_max) { + idx = (idx_max + idx_min) / 2; + idx1 = unicode_comp_table[idx]; + + /* idx1 represent an entry of the decomposition table */ + d_idx = idx1 >> 6; + d_offset = idx1 & 0x3f; + v = unicode_decomp_table1[d_idx]; + code = v >> (32 - 18); + len = (v >> (32 - 18 - 7)) & 0x7f; + type = (v >> (32 - 18 - 7 - 6)) & 0x3f; + ch = code + d_offset; + unicode_decomp_entry(pair, ch, d_idx, code, len, type); + d = c0 - pair[0]; + if (d == 0) + d = c1 - pair[1]; + if (d < 0) { + idx_max = idx - 1; + } else if (d > 0) { + idx_min = idx + 1; + } else { + return ch; + } + } + return 0; +} + +/* return the combining class of character c (between 0 and 255) */ +static int unicode_get_cc(uint32_t c) +{ + uint32_t code, n, type, cc, c1, b; + int pos; + const uint8_t *p; + + pos = get_index_pos(&code, c, + unicode_cc_index, sizeof(unicode_cc_index) / 3); + if (pos < 0) + return 0; + p = unicode_cc_table + pos; + for(;;) { + b = *p++; + type = b >> 6; + n = b & 0x3f; + if (n < 48) { + } else if (n < 56) { + n = (n - 48) << 8; + n |= *p++; + n += 48; + } else { + n = (n - 56) << 8; + n |= *p++ << 8; + n |= *p++; + n += 48 + (1 << 11); + } + if (type <= 1) + p++; + c1 = code + n + 1; + if (c < c1) { + switch(type) { + case 0: + cc = p[-1]; + break; + case 1: + cc = p[-1] + c - code; + break; + case 2: + cc = 0; + break; + default: + case 3: + cc = 230; + break; + } + return cc; + } + code = c1; + } +} + +static void sort_cc(int *buf, int len) +{ + int i, j, k, cc, cc1, start, ch1; + + for(i = 0; i < len; i++) { + cc = unicode_get_cc(buf[i]); + if (cc != 0) { + start = i; + j = i + 1; + while (j < len) { + ch1 = buf[j]; + cc1 = unicode_get_cc(ch1); + if (cc1 == 0) + break; + k = j - 1; + while (k >= start) { + if (unicode_get_cc(buf[k]) <= cc1) + break; + buf[k + 1] = buf[k]; + k--; + } + buf[k + 1] = ch1; + j++; + } + i = j; + } + } +} + +static void to_nfd_rec(DynBuf *dbuf, + const int *src, int src_len, int is_compat) +{ + uint32_t c, v; + int i, l; + uint32_t res[UNICODE_DECOMP_LEN_MAX]; + + for(i = 0; i < src_len; i++) { + c = src[i]; + if (c >= 0xac00 && c < 0xd7a4) { + /* Hangul decomposition */ + c -= 0xac00; + dbuf_put_u32(dbuf, 0x1100 + c / 588); + dbuf_put_u32(dbuf, 0x1161 + (c % 588) / 28); + v = c % 28; + if (v != 0) + dbuf_put_u32(dbuf, 0x11a7 + v); + } else { + l = unicode_decomp_char(res, c, is_compat); + if (l) { + to_nfd_rec(dbuf, (int *)res, l, is_compat); + } else { + dbuf_put_u32(dbuf, c); + } + } + } +} + +/* return 0 if not found */ +static int compose_pair(uint32_t c0, uint32_t c1) +{ + /* Hangul composition */ + if (c0 >= 0x1100 && c0 < 0x1100 + 19 && + c1 >= 0x1161 && c1 < 0x1161 + 21) { + return 0xac00 + (c0 - 0x1100) * 588 + (c1 - 0x1161) * 28; + } else if (c0 >= 0xac00 && c0 < 0xac00 + 11172 && + (c0 - 0xac00) % 28 == 0 && + c1 >= 0x11a7 && c1 < 0x11a7 + 28) { + return c0 + c1 - 0x11a7; + } else { + return unicode_compose_pair(c0, c1); + } +} + +int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, + UnicodeNormalizationEnum n_type, + void *opaque, DynBufReallocFunc *realloc_func) +{ + int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len; + bool is_compat; + DynBuf dbuf_s, *dbuf = &dbuf_s; + + is_compat = n_type >> 1; + + dbuf_init2(dbuf, opaque, realloc_func); + if (dbuf_realloc(dbuf, sizeof(int) * src_len)) + goto fail; + + /* common case: latin1 is unaffected by NFC */ + if (n_type == UNICODE_NFC) { + for(i = 0; i < src_len; i++) { + if (src[i] >= 0x100) + goto not_latin1; + } + buf = (int *)dbuf->buf; + memcpy(buf, src, src_len * sizeof(int)); + *pdst = (uint32_t *)buf; + return src_len; + not_latin1: ; + } + + to_nfd_rec(dbuf, (const int *)src, src_len, is_compat); + if (dbuf_error(dbuf)) { + fail: + *pdst = NULL; + return -1; + } + buf = (int *)dbuf->buf; + buf_len = dbuf->size / sizeof(int); + + sort_cc(buf, buf_len); + + if (buf_len <= 1 || (n_type & 1) != 0) { + /* NFD / NFKD */ + *pdst = (uint32_t *)buf; + return buf_len; + } + + i = 1; + out_len = 1; + while (i < buf_len) { + /* find the starter character and test if it is blocked from + the character at 'i' */ + last_cc = unicode_get_cc(buf[i]); + starter_pos = out_len - 1; + while (starter_pos >= 0) { + cc = unicode_get_cc(buf[starter_pos]); + if (cc == 0) + break; + if (cc >= last_cc) + goto next; + last_cc = 256; + starter_pos--; + } + if (starter_pos >= 0 && + (p = compose_pair(buf[starter_pos], buf[i])) != 0) { + buf[starter_pos] = p; + i++; + } else { + next: + buf[out_len++] = buf[i++]; + } + } + *pdst = (uint32_t *)buf; + return out_len; +} + +/* char ranges for various unicode properties */ + +static int unicode_find_name(const char *name_table, const char *name) +{ + const char *p, *r; + int pos; + size_t name_len, len; + + p = name_table; + pos = 0; + name_len = strlen(name); + while (*p) { + for(;;) { + r = strchr(p, ','); + if (!r) + len = strlen(p); + else + len = r - p; + if (len == name_len && !memcmp(p, name, name_len)) + return pos; + p += len + 1; + if (!r) + break; + } + pos++; + } + return -1; +} + +/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 + if not found */ +int unicode_script(CharRange *cr, + const char *script_name, bool is_ext) +{ + int script_idx; + const uint8_t *p, *p_end; + uint32_t c, c1, b, n, v, v_len, i, type; + CharRange cr1_s = { 0 }, *cr1 = NULL; + CharRange cr2_s = { 0 }, *cr2 = &cr2_s; + bool is_common; + + script_idx = unicode_find_name(unicode_script_name_table, script_name); + if (script_idx < 0) + return -2; + /* Note: we remove the "Unknown" Script */ + script_idx += UNICODE_SCRIPT_Unknown + 1; + + is_common = (script_idx == UNICODE_SCRIPT_Common || + script_idx == UNICODE_SCRIPT_Inherited); + if (is_ext) { + cr1 = &cr1_s; + cr_init(cr1, cr->mem_opaque, cr->realloc_func); + cr_init(cr2, cr->mem_opaque, cr->realloc_func); + } else { + cr1 = cr; + } + + p = unicode_script_table; + p_end = unicode_script_table + countof(unicode_script_table); + c = 0; + while (p < p_end) { + b = *p++; + type = b >> 7; + n = b & 0x7f; + if (n < 96) { + } else if (n < 112) { + n = (n - 96) << 8; + n |= *p++; + n += 96; + } else { + n = (n - 112) << 16; + n |= *p++ << 8; + n |= *p++; + n += 96 + (1 << 12); + } + if (type == 0) + v = 0; + else + v = *p++; + c1 = c + n + 1; + if (v == script_idx) { + if (cr_add_interval(cr1, c, c1)) + goto fail; + } + c = c1; + } + + if (is_ext) { + /* add the script extensions */ + p = unicode_script_ext_table; + p_end = unicode_script_ext_table + countof(unicode_script_ext_table); + c = 0; + while (p < p_end) { + b = *p++; + if (b < 128) { + n = b; + } else if (b < 128 + 64) { + n = (b - 128) << 8; + n |= *p++; + n += 128; + } else { + n = (b - 128 - 64) << 16; + n |= *p++ << 8; + n |= *p++; + n += 128 + (1 << 14); + } + c1 = c + n + 1; + v_len = *p++; + if (is_common) { + if (v_len != 0) { + if (cr_add_interval(cr2, c, c1)) + goto fail; + } + } else { + for(i = 0; i < v_len; i++) { + if (p[i] == script_idx) { + if (cr_add_interval(cr2, c, c1)) + goto fail; + break; + } + } + } + p += v_len; + c = c1; + } + if (is_common) { + /* remove all the characters with script extensions */ + if (cr_invert(cr2)) + goto fail; + if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len, + CR_OP_INTER)) + goto fail; + } else { + if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len, + CR_OP_UNION)) + goto fail; + } + cr_free(cr1); + cr_free(cr2); + } + return 0; + fail: + if (is_ext) { + cr_free(cr1); + cr_free(cr2); + } + goto fail; +} + +#define M(id) (1U << UNICODE_GC_ ## id) + +static int unicode_general_category1(CharRange *cr, uint32_t gc_mask) +{ + const uint8_t *p, *p_end; + uint32_t c, c0, b, n, v; + + p = unicode_gc_table; + p_end = unicode_gc_table + countof(unicode_gc_table); + c = 0; + while (p < p_end) { + b = *p++; + n = b >> 5; + v = b & 0x1f; + if (n == 7) { + n = *p++; + if (n < 128) { + n += 7; + } else if (n < 128 + 64) { + n = (n - 128) << 8; + n |= *p++; + n += 7 + 128; + } else { + n = (n - 128 - 64) << 16; + n |= *p++ << 8; + n |= *p++; + n += 7 + 128 + (1 << 14); + } + } + c0 = c; + c += n + 1; + if (v == 31) { + /* run of Lu / Ll */ + b = gc_mask & (M(Lu) | M(Ll)); + if (b != 0) { + if (b == (M(Lu) | M(Ll))) { + goto add_range; + } else { + c0 += ((gc_mask & M(Ll)) != 0); + for(; c0 < c; c0 += 2) { + if (cr_add_interval(cr, c0, c0 + 1)) + return -1; + } + } + } + } else if ((gc_mask >> v) & 1) { + add_range: + if (cr_add_interval(cr, c0, c)) + return -1; + } + } + return 0; +} + +static int unicode_prop1(CharRange *cr, int prop_idx) +{ + const uint8_t *p, *p_end; + uint32_t c, c0, b, bit; + + p = unicode_prop_table[prop_idx]; + p_end = p + unicode_prop_len_table[prop_idx]; + c = 0; + bit = 0; + while (p < p_end) { + c0 = c; + b = *p++; + if (b < 64) { + c += (b >> 3) + 1; + if (bit) { + if (cr_add_interval(cr, c0, c)) + return -1; + } + bit ^= 1; + c0 = c; + c += (b & 7) + 1; + } else if (b >= 0x80) { + c += b - 0x80 + 1; + } else if (b < 0x60) { + c += (((b - 0x40) << 8) | p[0]) + 1; + p++; + } else { + c += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1; + p += 2; + } + if (bit) { + if (cr_add_interval(cr, c0, c)) + return -1; + } + bit ^= 1; + } + return 0; +} + +#define CASE_U (1 << 0) +#define CASE_L (1 << 1) +#define CASE_F (1 << 2) + +/* use the case conversion table to generate range of characters. + CASE_U: set char if modified by uppercasing, + CASE_L: set char if modified by lowercasing, + CASE_F: set char if modified by case folding, + */ +static int unicode_case1(CharRange *cr, int case_mask) +{ +#define MR(x) (1 << RUN_TYPE_ ## x) + const uint32_t tab_run_mask[3] = { + MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) | + MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3), + + MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2), + + MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3), + }; +#undef MR + uint32_t mask, v, code, type, len, i, idx; + + if (case_mask == 0) + return 0; + mask = 0; + for(i = 0; i < 3; i++) { + if ((case_mask >> i) & 1) + mask |= tab_run_mask[i]; + } + for(idx = 0; idx < countof(case_conv_table1); idx++) { + v = case_conv_table1[idx]; + type = (v >> (32 - 17 - 7 - 4)) & 0xf; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + if ((mask >> type) & 1) { + // printf("%d: type=%d %04x %04x\n", idx, type, code, code + len - 1); + switch(type) { + case RUN_TYPE_UL: + if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F))) + goto def_case; + code += ((case_mask & CASE_U) != 0); + for(i = 0; i < len; i += 2) { + if (cr_add_interval(cr, code + i, code + i + 1)) + return -1; + } + break; + case RUN_TYPE_LSU: + if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F))) + goto def_case; + if (!(case_mask & CASE_U)) { + if (cr_add_interval(cr, code, code + 1)) + return -1; + } + if (cr_add_interval(cr, code + 1, code + 2)) + return -1; + if (case_mask & CASE_U) { + if (cr_add_interval(cr, code + 2, code + 3)) + return -1; + } + break; + default: + def_case: + if (cr_add_interval(cr, code, code + len)) + return -1; + break; + } + } + } + return 0; +} + +static int point_cmp(const void *p1, const void *p2, void *arg) +{ + uint32_t v1 = *(uint32_t *)p1; + uint32_t v2 = *(uint32_t *)p2; + return (v1 > v2) - (v1 < v2); +} + +static void cr_sort_and_remove_overlap(CharRange *cr) +{ + uint32_t start, end, start1, end1, i, j; + + /* the resulting ranges are not necessarily sorted and may overlap */ + rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL); + j = 0; + for(i = 0; i < cr->len; ) { + start = cr->points[i]; + end = cr->points[i + 1]; + i += 2; + while (i < cr->len) { + start1 = cr->points[i]; + end1 = cr->points[i + 1]; + if (start1 > end) { + /* |------| + * |-------| */ + break; + } else if (end1 <= end) { + /* |------| + * |--| */ + i += 2; + } else { + /* |------| + * |-------| */ + end = end1; + i += 2; + } + } + cr->points[j] = start; + cr->points[j + 1] = end; + j += 2; + } + cr->len = j; +} + +/* canonicalize a character set using the JS regex case folding rules + (see lre_canonicalize()) */ +int cr_regexp_canonicalize(CharRange *cr, bool is_unicode) +{ + CharRange cr_inter, cr_mask, cr_result, cr_sub; + uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d; + + cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func); + cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func); + cr_init(&cr_result, cr->mem_opaque, cr->realloc_func); + cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func); + + if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U)) + goto fail; + if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER)) + goto fail; + + if (cr_invert(&cr_mask)) + goto fail; + if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER)) + goto fail; + + /* cr_inter = cr & cr_mask */ + /* cr_sub = cr & ~cr_mask */ + + /* use the case conversion table to compute the result */ + d_start = -1; + d_end = -1; + idx = 0; + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + for(i = 0; i < cr_inter.len; i += 2) { + start = cr_inter.points[i]; + end = cr_inter.points[i + 1]; + + for(c = start; c < end; c++) { + for(;;) { + if (c >= code && c < code + len) + break; + idx++; + assert(idx < countof(case_conv_table1)); + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + } + d = lre_case_folding_entry(c, idx, v, is_unicode); + /* try to merge with the current interval */ + if (d_start == -1) { + d_start = d; + d_end = d + 1; + } else if (d_end == d) { + d_end++; + } else { + cr_add_interval(&cr_result, d_start, d_end); + d_start = d; + d_end = d + 1; + } + } + } + if (d_start != -1) { + if (cr_add_interval(&cr_result, d_start, d_end)) + goto fail; + } + + /* the resulting ranges are not necessarily sorted and may overlap */ + cr_sort_and_remove_overlap(&cr_result); + + /* or with the character not affected by the case folding */ + cr->len = 0; + if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION)) + goto fail; + + cr_free(&cr_inter); + cr_free(&cr_mask); + cr_free(&cr_result); + cr_free(&cr_sub); + return 0; + fail: + cr_free(&cr_inter); + cr_free(&cr_mask); + cr_free(&cr_result); + cr_free(&cr_sub); + return -1; +} + +typedef enum { + POP_GC, + POP_PROP, + POP_CASE, + POP_UNION, + POP_INTER, + POP_XOR, + POP_INVERT, + POP_END, +} PropOPEnum; + +#define POP_STACK_LEN_MAX 4 + +static int unicode_prop_ops(CharRange *cr, ...) +{ + va_list ap; + CharRange stack[POP_STACK_LEN_MAX]; + int stack_len, op, ret, i; + uint32_t a; + + va_start(ap, cr); + stack_len = 0; + for(;;) { + op = va_arg(ap, int); + switch(op) { + case POP_GC: + assert(stack_len < POP_STACK_LEN_MAX); + a = va_arg(ap, int); + cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); + if (unicode_general_category1(&stack[stack_len - 1], a)) + goto fail; + break; + case POP_PROP: + assert(stack_len < POP_STACK_LEN_MAX); + a = va_arg(ap, int); + cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); + if (unicode_prop1(&stack[stack_len - 1], a)) + goto fail; + break; + case POP_CASE: + assert(stack_len < POP_STACK_LEN_MAX); + a = va_arg(ap, int); + cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); + if (unicode_case1(&stack[stack_len - 1], a)) + goto fail; + break; + case POP_UNION: + case POP_INTER: + case POP_XOR: + { + CharRange *cr1, *cr2, *cr3; + assert(stack_len >= 2); + assert(stack_len < POP_STACK_LEN_MAX); + cr1 = &stack[stack_len - 2]; + cr2 = &stack[stack_len - 1]; + cr3 = &stack[stack_len++]; + cr_init(cr3, cr->mem_opaque, cr->realloc_func); + if (cr_op(cr3, cr1->points, cr1->len, + cr2->points, cr2->len, op - POP_UNION + CR_OP_UNION)) + goto fail; + cr_free(cr1); + cr_free(cr2); + *cr1 = *cr3; + stack_len -= 2; + } + break; + case POP_INVERT: + assert(stack_len >= 1); + if (cr_invert(&stack[stack_len - 1])) + goto fail; + break; + case POP_END: + goto done; + default: + abort(); + } + } + done: + va_end(ap); + assert(stack_len == 1); + ret = cr_copy(cr, &stack[0]); + cr_free(&stack[0]); + return ret; + fail: + va_end(ap); + for(i = 0; i < stack_len; i++) + cr_free(&stack[i]); + return -1; +} + +static const uint32_t unicode_gc_mask_table[] = { + M(Lu) | M(Ll) | M(Lt), /* LC */ + M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo), /* L */ + M(Mn) | M(Mc) | M(Me), /* M */ + M(Nd) | M(Nl) | M(No), /* N */ + M(Sm) | M(Sc) | M(Sk) | M(So), /* S */ + M(Pc) | M(Pd) | M(Ps) | M(Pe) | M(Pi) | M(Pf) | M(Po), /* P */ + M(Zs) | M(Zl) | M(Zp), /* Z */ + M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn), /* C */ +}; + +/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 + if not found */ +int unicode_general_category(CharRange *cr, const char *gc_name) +{ + int gc_idx; + uint32_t gc_mask; + + gc_idx = unicode_find_name(unicode_gc_name_table, gc_name); + if (gc_idx < 0) + return -2; + if (gc_idx <= UNICODE_GC_Co) { + gc_mask = (uint64_t)1 << gc_idx; + } else { + gc_mask = unicode_gc_mask_table[gc_idx - UNICODE_GC_LC]; + } + return unicode_general_category1(cr, gc_mask); +} + + +/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 + if not found */ +int unicode_prop(CharRange *cr, const char *prop_name) +{ + int prop_idx, ret; + + prop_idx = unicode_find_name(unicode_prop_name_table, prop_name); + if (prop_idx < 0) + return -2; + prop_idx += UNICODE_PROP_ASCII_Hex_Digit; + + ret = 0; + switch(prop_idx) { + case UNICODE_PROP_ASCII: + if (cr_add_interval(cr, 0x00, 0x7f + 1)) + return -1; + break; + case UNICODE_PROP_Any: + if (cr_add_interval(cr, 0x00000, 0x10ffff + 1)) + return -1; + break; + case UNICODE_PROP_Assigned: + ret = unicode_prop_ops(cr, + POP_GC, M(Cn), + POP_INVERT, + POP_END); + break; + case UNICODE_PROP_Math: + ret = unicode_prop_ops(cr, + POP_GC, M(Sm), + POP_PROP, UNICODE_PROP_Other_Math, + POP_UNION, + POP_END); + break; + case UNICODE_PROP_Lowercase: + ret = unicode_prop_ops(cr, + POP_GC, M(Ll), + POP_PROP, UNICODE_PROP_Other_Lowercase, + POP_UNION, + POP_END); + break; + case UNICODE_PROP_Uppercase: + ret = unicode_prop_ops(cr, + POP_GC, M(Lu), + POP_PROP, UNICODE_PROP_Other_Uppercase, + POP_UNION, + POP_END); + break; + case UNICODE_PROP_Cased: + ret = unicode_prop_ops(cr, + POP_GC, M(Lu) | M(Ll) | M(Lt), + POP_PROP, UNICODE_PROP_Other_Uppercase, + POP_UNION, + POP_PROP, UNICODE_PROP_Other_Lowercase, + POP_UNION, + POP_END); + break; + case UNICODE_PROP_Alphabetic: + ret = unicode_prop_ops(cr, + POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), + POP_PROP, UNICODE_PROP_Other_Uppercase, + POP_UNION, + POP_PROP, UNICODE_PROP_Other_Lowercase, + POP_UNION, + POP_PROP, UNICODE_PROP_Other_Alphabetic, + POP_UNION, + POP_END); + break; + case UNICODE_PROP_Grapheme_Base: + ret = unicode_prop_ops(cr, + POP_GC, M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn) | M(Zl) | M(Zp) | M(Me) | M(Mn), + POP_PROP, UNICODE_PROP_Other_Grapheme_Extend, + POP_UNION, + POP_INVERT, + POP_END); + break; + case UNICODE_PROP_Grapheme_Extend: + ret = unicode_prop_ops(cr, + POP_GC, M(Me) | M(Mn), + POP_PROP, UNICODE_PROP_Other_Grapheme_Extend, + POP_UNION, + POP_END); + break; + case UNICODE_PROP_XID_Start: + ret = unicode_prop_ops(cr, + POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), + POP_PROP, UNICODE_PROP_Other_ID_Start, + POP_UNION, + POP_PROP, UNICODE_PROP_Pattern_Syntax, + POP_PROP, UNICODE_PROP_Pattern_White_Space, + POP_UNION, + POP_PROP, UNICODE_PROP_XID_Start1, + POP_UNION, + POP_INVERT, + POP_INTER, + POP_END); + break; + case UNICODE_PROP_XID_Continue: + ret = unicode_prop_ops(cr, + POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) | + M(Mn) | M(Mc) | M(Nd) | M(Pc), + POP_PROP, UNICODE_PROP_Other_ID_Start, + POP_UNION, + POP_PROP, UNICODE_PROP_Other_ID_Continue, + POP_UNION, + POP_PROP, UNICODE_PROP_Pattern_Syntax, + POP_PROP, UNICODE_PROP_Pattern_White_Space, + POP_UNION, + POP_PROP, UNICODE_PROP_XID_Continue1, + POP_UNION, + POP_INVERT, + POP_INTER, + POP_END); + break; + case UNICODE_PROP_Changes_When_Uppercased: + ret = unicode_case1(cr, CASE_U); + break; + case UNICODE_PROP_Changes_When_Lowercased: + ret = unicode_case1(cr, CASE_L); + break; + case UNICODE_PROP_Changes_When_Casemapped: + ret = unicode_case1(cr, CASE_U | CASE_L | CASE_F); + break; + case UNICODE_PROP_Changes_When_Titlecased: + ret = unicode_prop_ops(cr, + POP_CASE, CASE_U, + POP_PROP, UNICODE_PROP_Changes_When_Titlecased1, + POP_XOR, + POP_END); + break; + case UNICODE_PROP_Changes_When_Casefolded: + ret = unicode_prop_ops(cr, + POP_CASE, CASE_F, + POP_PROP, UNICODE_PROP_Changes_When_Casefolded1, + POP_XOR, + POP_END); + break; + case UNICODE_PROP_Changes_When_NFKC_Casefolded: + ret = unicode_prop_ops(cr, + POP_CASE, CASE_F, + POP_PROP, UNICODE_PROP_Changes_When_NFKC_Casefolded1, + POP_XOR, + POP_END); + break; + /* we use the existing tables */ + case UNICODE_PROP_ID_Continue: + ret = unicode_prop_ops(cr, + POP_PROP, UNICODE_PROP_ID_Start, + POP_PROP, UNICODE_PROP_ID_Continue1, + POP_XOR, + POP_END); + break; + default: + if (prop_idx >= countof(unicode_prop_table)) + return -2; + ret = unicode_prop1(cr, prop_idx); + break; + } + return ret; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/libunicode.h b/host/cred-script/vendor/rquickjs-sys/quickjs/libunicode.h new file mode 100644 index 0000000..8e6f2a0 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/libunicode.h @@ -0,0 +1,126 @@ +/* + * Unicode utilities + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef LIBUNICODE_H +#define LIBUNICODE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LRE_CC_RES_LEN_MAX 3 + +typedef enum { + UNICODE_NFC, + UNICODE_NFD, + UNICODE_NFKC, + UNICODE_NFKD, +} UnicodeNormalizationEnum; + +int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); +int lre_canonicalize(uint32_t c, bool is_unicode); +bool lre_is_cased(uint32_t c); +bool lre_is_case_ignorable(uint32_t c); + +/* char ranges */ + +typedef struct { + int len; /* in points, always even */ + int size; + uint32_t *points; /* points sorted by increasing value */ + void *mem_opaque; + void *(*realloc_func)(void *opaque, void *ptr, size_t size); +} CharRange; + +typedef enum { + CR_OP_UNION, + CR_OP_INTER, + CR_OP_XOR, +} CharRangeOpEnum; + +void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); +void cr_free(CharRange *cr); +int cr_realloc(CharRange *cr, int size); +int cr_copy(CharRange *cr, const CharRange *cr1); + +static inline int cr_add_point(CharRange *cr, uint32_t v) +{ + if (cr->len >= cr->size) { + if (cr_realloc(cr, cr->len + 1)) + return -1; + } + cr->points[cr->len++] = v; + return 0; +} + +static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2) +{ + if ((cr->len + 2) > cr->size) { + if (cr_realloc(cr, cr->len + 2)) + return -1; + } + cr->points[cr->len++] = c1; + cr->points[cr->len++] = c2; + return 0; +} + +int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len); + +static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2) +{ + uint32_t b_pt[2]; + b_pt[0] = c1; + b_pt[1] = c2 + 1; + return cr_union1(cr, b_pt, 2); +} + +int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, + const uint32_t *b_pt, int b_len, int op); + +int cr_invert(CharRange *cr); +int cr_regexp_canonicalize(CharRange *cr, bool is_unicode); + +bool lre_is_id_start(uint32_t c); +bool lre_is_id_continue(uint32_t c); +bool lre_is_white_space(uint32_t c); + +int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, + UnicodeNormalizationEnum n_type, + void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); + +/* Unicode character range functions */ + +int unicode_script(CharRange *cr, + const char *script_name, bool is_ext); +int unicode_general_category(CharRange *cr, const char *gc_name); +int unicode_prop(CharRange *cr, const char *prop_name); + +#ifdef __cplusplus +} /* extern "C" { */ +#endif + +#endif /* LIBUNICODE_H */ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/list.h b/host/cred-script/vendor/rquickjs-sys/quickjs/list.h new file mode 100644 index 0000000..b8dd716 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/list.h @@ -0,0 +1,107 @@ +/* + * Linux klist like system + * + * Copyright (c) 2016-2017 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef LIST_H +#define LIST_H + +#ifndef NULL +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +#define LIST_HEAD_INIT(el) { &(el), &(el) } + +/* return the pointer of type 'type *' containing 'el' as field 'member' */ +#define list_entry(el, type, member) container_of(el, type, member) + +static inline void init_list_head(struct list_head *head) +{ + head->prev = head; + head->next = head; +} + +/* insert 'el' between 'prev' and 'next' */ +static inline void __list_add(struct list_head *el, + struct list_head *prev, struct list_head *next) +{ + prev->next = el; + el->prev = prev; + el->next = next; + next->prev = el; +} + +/* add 'el' at the head of the list 'head' (= after element head) */ +static inline void list_add(struct list_head *el, struct list_head *head) +{ + __list_add(el, head, head->next); +} + +/* add 'el' at the end of the list 'head' (= before element head) */ +static inline void list_add_tail(struct list_head *el, struct list_head *head) +{ + __list_add(el, head->prev, head); +} + +static inline void list_del(struct list_head *el) +{ + struct list_head *prev, *next; + prev = el->prev; + next = el->next; + prev->next = next; + next->prev = prev; + el->prev = NULL; /* fail safe */ + el->next = NULL; /* fail safe */ +} + +static inline int list_empty(struct list_head *el) +{ + return el->next == el; +} + +#define list_for_each(el, head) \ + for(el = (head)->next; el != (head); el = el->next) + +#define list_for_each_safe(el, el1, head) \ + for(el = (head)->next, el1 = el->next; el != (head); \ + el = el1, el1 = el->next) + +#define list_for_each_prev(el, head) \ + for(el = (head)->prev; el != (head); el = el->prev) + +#define list_for_each_prev_safe(el, el1, head) \ + for(el = (head)->prev, el1 = el->prev; el != (head); \ + el = el1, el1 = el->prev) + +#ifdef __cplusplus +} /* extern "C" { */ +#endif + +#endif /* LIST_H */ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/meson.build b/host/cred-script/vendor/rquickjs-sys/quickjs/meson.build new file mode 100644 index 0000000..1c17851 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/meson.build @@ -0,0 +1,635 @@ +project( + 'quickjs-ng', + 'c', + version: '0.11.0', + default_options: [ + 'c_std=gnu11,c11', + 'warning_level=3', + 'default_library=static', + ], + license: 'MIT', + license_files: 'LICENSE', + meson_version: '>=1.3.0', +) + +host_system = host_machine.system() +cc = meson.get_compiler('c') + +qjs_gcc_warning_args = [ + '-Wno-unsafe-buffer-usage', + '-Wno-sign-conversion', + '-Wno-nonportable-system-include-path', + '-Wno-implicit-int-conversion', + '-Wno-shorten-64-to-32', + '-Wno-reserved-macro-identifier', + '-Wno-reserved-identifier', + '-Wdeprecated-declarations', + + '-Wno-implicit-fallthrough', + '-Wno-sign-compare', + '-Wno-missing-field-initializers', + '-Wno-unused-parameter', + '-Wno-unused-but-set-variable', + '-Wno-array-bounds', + '-Wno-format-truncation', +] +qjs_gcc_args = [ + '-funsigned-char', +] + +if host_system == 'darwin' + # https://github.com/quickjs-ng/quickjs/issues/453 + qjs_gcc_warning_args += '-Wno-maybe-uninitialized' +endif + +# https://github.com/microsoft/cpp-docs/tree/main/docs/error-messages/compiler-warnings +qjs_msvc_warning_args = [ + '/wd4018', # -Wno-sign-conversion + '/wd4061', # -Wno-implicit-fallthrough + '/wd4100', # -Wno-unused-parameter + '/wd4200', # -Wno-zero-length-array + '/wd4242', # -Wno-shorten-64-to-32 + '/wd4244', # -Wno-shorten-64-to-32 + '/wd4245', # -Wno-sign-compare + '/wd4267', # -Wno-shorten-64-to-32 + '/wd4388', # -Wno-sign-compare + '/wd4389', # -Wno-sign-compare + '/wd4710', # Function not inlined + '/wd4711', # Function was inlined + '/wd4820', # Padding added after construct + '/wd4996', # -Wdeprecated-declarations + '/wd5045', # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +] +qjs_msvc_args = [ + '/experimental:c11atomics', + '/J', # -funsigned-char +] + +if cc.get_argument_syntax() == 'msvc' + add_project_arguments( + cc.get_supported_arguments(qjs_msvc_warning_args), + cc.get_id().contains('clang') ? cc.get_supported_arguments(qjs_gcc_warning_args) : [], + qjs_msvc_args, + language: 'c', + ) +else + add_project_arguments( + cc.get_supported_arguments(qjs_gcc_warning_args), + qjs_gcc_args, + language: 'c', + ) +endif + +if host_system == 'windows' + # Set a 8MB default stack size on Windows. + # It defaults to 1MB on MSVC, which is the same as our current JS stack size, + # so it will overflow and crash otherwise. + # On MinGW it defaults to 2MB. + stack_size = 8 * 1024 * 1024 + if cc.get_argument_syntax() == 'msvc' + add_project_link_arguments(f'/STACK:@stack_size@', language: 'c') + else + add_project_link_arguments(f'-Wl,--stack,@stack_size@', language: 'c') + endif +endif + +if meson.is_cross_build() + native_cc = meson.get_compiler('c', native: true) + + if native_cc.get_argument_syntax() == 'msvc' + # https://github.com/microsoft/cpp-docs/tree/main/docs/error-messages/compiler-warnings + add_project_arguments( + native_cc.get_supported_arguments(qjs_msvc_warning_args), + native_cc.get_id().contains('clang') ? native_cc.get_supported_arguments(qjs_gcc_warning_args) : [], + qjs_msvc_args, + + language: 'c', + native: true, + ) + else + add_project_arguments( + native_cc.get_supported_arguments(qjs_gcc_warning_args), + qjs_gcc_args, + + language: 'c', + native: true, + ) + endif +endif +if get_option('debug') + add_project_arguments( + cc.get_supported_arguments('-fno-omit-frame-pointer'), + language: 'c', + ) +endif + +qjs_sys_deps = [] + +m_dep = cc.find_library('m', required: false) +qjs_sys_deps += m_dep +qjs_sys_deps += dependency('threads', required: false) +qjs_sys_deps += dependency('dl', required: false) + +qjs_srcs = files( + 'cutils.c', + 'dtoa.c', + 'libregexp.c', + 'libunicode.c', + 'quickjs.c', +) +qjs_hdrs = files( + 'quickjs.h', +) + +qjs_libc = get_option('libc') +qjs_libc_srcs = files('quickjs-libc.c') +qjs_libc_hdrs = files('quickjs-libc.h') + +if qjs_libc + qjs_hdrs += qjs_libc_hdrs +endif + +qjs_parser = get_option('parser') + +qjs_c_args = ['-D_GNU_SOURCE'] + +if host_system == 'windows' + qjs_c_args += ['-DWIN32_LEAN_AND_MEAN', '-D_WIN32_WINNT=0x0601'] +endif + +if not qjs_parser + qjs_c_args += ['-DQJS_DISABLE_PARSER'] +endif + +qjs_libc_lib = static_library( + 'quickjs-libc', + qjs_libc_srcs, + + dependencies: qjs_sys_deps, + c_args: qjs_c_args, + gnu_symbol_visibility: 'hidden', +) + +qjs_lib = library( + 'qjs', + qjs_srcs, + + # export public headers + generator( + find_program('cp', 'xcopy'), + output: ['@PLAINNAME@'], + arguments: ['@INPUT@', '@OUTPUT@'], + ).process(qjs_hdrs), + + dependencies: qjs_sys_deps, + link_whole: qjs_libc ? qjs_libc_lib : [], + c_args: qjs_c_args, + gnu_symbol_visibility: 'hidden', + + install: true, + version: meson.project_version(), +) + +qjs_export_variables = [ + f'have_parser=@qjs_parser@' +] + +qjs_dep = declare_dependency( + link_with: qjs_lib, + dependencies: qjs_sys_deps, + include_directories: qjs_lib.private_dir_include(), + variables: qjs_export_variables, +) + +if host_system == 'emscripten' + qjs_wasm_export_name = 'getQuickJs' + executable( + 'qjs_wasm', + qjs_srcs, + link_args: cc.get_supported_link_arguments( + # in emscripten 3.x, this will be set to 16k which is too small for quickjs. + '-sSTACK_SIZE=@0@'.format(2 * 1024 * 1024), # let it be 2m = 2 * 1024 * 1024, otherwise, stack overflow may be occured at bootstrap + '-sNO_INVOKE_RUN', + '-sNO_EXIT_RUNTIME', + '-sMODULARIZE', # do not mess the global + '-sEXPORT_ES6', # export js file to morden es module + '-sEXPORT_NAME=@0@'.format(qjs_wasm_export_name), # give a name + '-sTEXTDECODER=1', # it will be 2 if we use -Oz, and that will cause js -> c string convertion fail + '-sNO_DEFAULT_TO_CXX', # this project is pure c project, no need for c plus plus handle + '-sEXPORTED_RUNTIME_METHODS=ccall,cwrap', + ), + dependencies: m_dep, + c_args: qjs_c_args, + ) +endif + +install_headers(qjs_hdrs, subdir: 'quickjs-ng') + +if not meson.is_subproject() + docdir = get_option('docdir') + datadir = get_option('datadir') + + if docdir == '' + docdir = datadir / 'doc' / meson.project_name() + endif + install_data( + 'LICENSE', + install_dir: docdir, + + install_tag: 'doc', + ) + install_subdir( + 'examples', + install_dir: docdir, + + strip_directory: false, + install_tag: 'doc', + ) +endif + +meson.override_dependency('quickjs-ng', qjs_dep) + +import('pkgconfig').generate( + qjs_lib, + subdirs: 'quickjs-ng', + name: 'quickjs-ng', + description: 'QuickJS, the Next Generation: a mighty JavaScript engine', + url: 'https://github.com/quickjs-ng/quickjs', + version: meson.project_version(), + variables: qjs_export_variables, +) + +if not qjs_parser + subdir_done() +endif + +# QuickJS bytecode compiler +qjsc_srcs = files( + 'qjsc.c', +) +qjsc_exe = executable( + 'qjsc', + qjsc_srcs, + + c_args: qjs_c_args, + link_with: qjs_libc ? [] : qjs_libc_lib, + dependencies: qjs_dep, + + install: true, +) + +mimalloc_dep = [] +mimalloc_sys_dep = dependency('mimalloc', required: get_option('cli_mimalloc')) +if mimalloc_sys_dep.found() + mimalloc_dep = declare_dependency( + dependencies: mimalloc_sys_dep, + compile_args: '-DQJS_USE_MIMALLOC', + ) +endif + +# QuickJS CLI +qjs_exe_srcs = files( + 'gen/repl.c', + 'gen/standalone.c', + 'qjs.c', +) +qjs_exe = executable( + 'qjs', + qjs_exe_srcs, + + c_args: qjs_c_args, + link_with: qjs_libc ? [] : qjs_libc_lib, + dependencies: [qjs_dep, mimalloc_dep], + export_dynamic: true, + + install: true, +) + +if meson.is_cross_build() + mimalloc_native_dep = [] + mimalloc_sys_native_dep = dependency('mimalloc', required: get_option('cli_mimalloc'), native: true) + if mimalloc_sys_dep.found() + mimalloc_native_dep = declare_dependency( + dependencies: mimalloc_sys_native_dep, + compile_args: '-DQJS_USE_MIMALLOC', + ) + endif + + qjs_sys_native_deps = [ + native_cc.find_library('m', required: false), + dependency('threads', required: false, native: true), + dependency('dl', required: false, native: true), + ] + qjs_native_lib = static_library( + 'qjs_native', + qjs_srcs, + qjs_libc_srcs, + + dependencies: qjs_sys_native_deps, + c_args: qjs_c_args, + gnu_symbol_visibility: 'hidden', + + build_by_default: false, + native: true, + install: false, + ) + + meson.override_find_program( + 'qjsc', + executable( + 'qjsc_native', + qjsc_srcs, + + c_args: qjs_c_args, + link_with: qjs_native_lib, + dependencies: qjs_sys_native_deps, + + build_by_default: false, + native: true, + install: false, + ), + ) + meson.override_find_program( + 'qjs', + executable( + 'qjs_native', + qjs_exe_srcs, + + c_args: qjs_c_args, + link_with: qjs_native_lib, + dependencies: [qjs_sys_native_deps, mimalloc_native_dep], + export_dynamic: true, + + build_by_default: false, + native: true, + install: false, + ), + ) +else + meson.override_find_program('qjsc', qjsc_exe) + meson.override_find_program('qjs', qjs_exe) +endif + +tests = get_option('tests').disable_auto_if(meson.is_subproject()) +examples = get_option('examples').disable_auto_if(meson.is_subproject()) + +if tests.allowed() + if host_system != 'emscripten' + # Test262 runner + run262_exe = executable( + 'run-test262', + 'run-test262.c', + qjs_libc_srcs, + + c_args: qjs_c_args, + dependencies: qjs_dep, + ) + + test( + 'test', + run262_exe, + args: ['-c', files('tests.conf')], + workdir: meson.current_source_dir(), + ) + + foreach bench : [ + 'empty_loop', + + 'date_now', + + 'prop_read', + 'prop_write', + 'prop_create', + 'prop_delete', + + 'array_read', + 'array_write', + 'array_prop_create', + 'array_length_decr', + 'array_hole_length_decr', + 'array_push', + 'array_pop', + + 'typed_array_read', + 'typed_array_write', + + 'global_read', + 'global_write', + 'global_write_strict', + + 'local_destruct', + 'global_destruct', + 'global_destruct_strict', + + 'func_call', + 'closure_var', + + 'int_arith', + 'float_arith', + + 'map_set', + 'map_delete', + 'weak_map_set', + 'weak_map_delete', + + 'array_for', + 'array_for_in', + 'array_for_of', + + 'math_min', + + 'object_null', + + 'regexp_ascii', + 'regexp_utf16', + + 'string_build1', + 'string_build2', + + 'string_slice1', + 'string_slice2', + 'string_slice3', + + 'sort_bench', + + 'int_to_string', + 'int_toString', + + 'float_to_string', + 'float_toString', + 'float_toFixed', + 'float_toPrecision', + 'float_toExponential', + + 'string_to_int', + 'string_to_float', + + 'bigint64_arith', + 'bigint256_arith', + ] + benchmark( + bench, + qjs_exe, + args: [files('tests/microbench.js'), bench], + ) + endforeach + endif + + # API test + test( + 'api', + executable( + 'api-test', + 'api-test.c', + + c_args: qjs_c_args, + dependencies: qjs_dep, + build_by_default: false, + ), + ) + + # Function.toString() test + test( + 'function_source', + executable( + 'function_source', + 'gen/function_source.c', + qjs_libc_srcs, + + c_args: qjs_c_args, + dependencies: qjs_dep, + build_by_default: false, + ), + ) +endif + +# Unicode generator +unicode_gen = executable( + 'unicode_gen', + 'cutils.c', + 'unicode_gen.c', + + c_args: qjs_c_args, + build_by_default: false, +) + +run_target( + 'libunicode-table.h', + command: [ + unicode_gen, + meson.current_source_dir() / 'unicode', + files('libunicode-table.h'), + ], +) + +# bytecode to c source code for builtin and examples +alias_target('codegen', + run_target( + 'codegen_repl.c', + command: [ + qjsc_exe, + '-ss', + '-o', files('gen/repl.c'), + '-m', + '-n', 'repl.js', + files('repl.js'), + ], + ), + run_target( + 'codegen_standalone.c', + command: [ + qjsc_exe, + '-ss', + '-o', files('gen/standalone.c'), + '-m', + '-n', 'standalone.js', + files('standalone.js'), + ], + ), + run_target( + 'codegen_function_source.c', + command: [ + qjsc_exe, + '-e', + '-o', files('gen/function_source.c'), + '-n', 'tests/function_source.js', + files('tests/function_source.js'), + ], + ), + run_target( + 'codegen_hello.c', + command: [ + qjsc_exe, + '-e', + '-o', files('gen/hello.c'), + '-n', 'examples/hello.js', + files('examples/hello.js'), + ], + ), + run_target( + 'codegen_hello_module.c', + command: [ + qjsc_exe, + '-e', + '-o', files('gen/hello_module.c'), + '-m', + '-n', 'examples/hello_module.js', + files('examples/hello_module.js'), + ], + ), + run_target( + 'codegen_test_fib.c', + command: [ + qjsc_exe, + '-e', + '-o', files('gen/test_fib.c'), + '-m', + '-n', 'examples/test_fib.js', + files('examples/test_fib.js'), + ], + ), + run_target( + 'codegen_builtin-array-fromasync.h', + command: [ + qjsc_exe, + '-C', + '-ss', + '-o', files('builtin-array-fromasync.h'), + '-n', 'builtin-array-fromasync.js', + files('builtin-array-fromasync.js'), + ], + ), +) + +if examples.allowed() + executable( + 'hello', + 'gen/hello.c', + qjs_libc_srcs, + + c_args: qjs_c_args, + dependencies: qjs_dep, + ) + + executable( + 'hello_module', + 'gen/hello_module.c', + qjs_libc_srcs, + + c_args: qjs_c_args, + dependencies: qjs_dep, + ) + + subdir('examples') + + executable( + 'test_fib', + 'examples/fib.c', + 'gen/test_fib.c', + qjs_libc_srcs, + + c_args: qjs_c_args, + dependencies: qjs_dep, + export_dynamic: true, + ) +endif diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/meson_options.txt b/host/cred-script/vendor/rquickjs-sys/quickjs/meson_options.txt new file mode 100644 index 0000000..20e661e --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/meson_options.txt @@ -0,0 +1,6 @@ +option('tests', type: 'feature', description: 'build tests') +option('examples', type: 'feature', description: 'build examples') +option('libc', type: 'boolean', value: false, description: 'build qjs standard library modules as part of the library') +option('cli_mimalloc', type: 'feature', value: 'disabled', description: 'build qjs cli with mimalloc') +option('docdir', type: 'string', description: 'documentation directory') +option('parser', type: 'boolean', value: true, description: 'Enable JS source code parser') diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/qjs.c b/host/cred-script/vendor/rquickjs-sys/quickjs/qjs.c new file mode 100644 index 0000000..4aed683 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/qjs.c @@ -0,0 +1,748 @@ +/* + * QuickJS stand alone interpreter + * + * Copyright (c) 2017-2021 Fabrice Bellard + * Copyright (c) 2017-2021 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cutils.h" +#include "quickjs.h" +#include "quickjs-libc.h" + +#ifdef QJS_USE_MIMALLOC +#include +#endif + +extern const uint8_t qjsc_repl[]; +extern const uint32_t qjsc_repl_size; +extern const uint8_t qjsc_standalone[]; +extern const uint32_t qjsc_standalone_size; + +// Must match standalone.js +#define TRAILER_SIZE 12 +static const char trailer_magic[] = "quickjs2"; +static const int trailer_magic_size = sizeof(trailer_magic) - 1; +static const int trailer_size = TRAILER_SIZE; + +static int qjs__argc; +static char **qjs__argv; + + +static bool is_standalone(const char *exe) +{ + FILE *exe_f = fopen(exe, "rb"); + if (!exe_f) + return false; + if (fseek(exe_f, -trailer_size, SEEK_END) < 0) + goto fail; + uint8_t buf[TRAILER_SIZE]; + if (fread(buf, 1, trailer_size, exe_f) != trailer_size) + goto fail; + fclose(exe_f); + return !memcmp(buf, trailer_magic, trailer_magic_size); +fail: + fclose(exe_f); + return false; +} + +static JSValue load_standalone_module(JSContext *ctx) +{ + JSModuleDef *m; + JSValue obj, val; + obj = JS_ReadObject(ctx, qjsc_standalone, qjsc_standalone_size, JS_READ_OBJ_BYTECODE); + if (JS_IsException(obj)) + goto exception; + assert(JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE); + if (JS_ResolveModule(ctx, obj) < 0) { + JS_FreeValue(ctx, obj); + goto exception; + } + if (js_module_set_import_meta(ctx, obj, false, true) < 0) { + JS_FreeValue(ctx, obj); + goto exception; + } + val = JS_EvalFunction(ctx, JS_DupValue(ctx, obj)); + val = js_std_await(ctx, val); + + if (JS_IsException(val)) { + JS_FreeValue(ctx, obj); + exception: + js_std_dump_error(ctx); + exit(1); + } + JS_FreeValue(ctx, val); + + m = JS_VALUE_GET_PTR(obj); + JS_FreeValue(ctx, obj); + return JS_GetModuleNamespace(ctx, m); +} + +static int eval_buf(JSContext *ctx, const void *buf, int buf_len, + const char *filename, int eval_flags) +{ + bool use_realpath; + JSValue val; + int ret; + + if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) { + /* for the modules, we compile then run to be able to set + import.meta */ + val = JS_Eval(ctx, buf, buf_len, filename, + eval_flags | JS_EVAL_FLAG_COMPILE_ONLY); + if (!JS_IsException(val)) { + // ex. "" pr "/dev/stdin" + use_realpath = + !(*filename == '<' || !strncmp(filename, "/dev/", 5)); + if (js_module_set_import_meta(ctx, val, use_realpath, true) < 0) { + js_std_dump_error(ctx); + ret = -1; + goto end; + } + val = JS_EvalFunction(ctx, val); + } + val = js_std_await(ctx, val); + } else { + val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); + } + if (JS_IsException(val)) { + js_std_dump_error(ctx); + ret = -1; + } else { + ret = 0; + } +end: + JS_FreeValue(ctx, val); + return ret; +} + +static int eval_file(JSContext *ctx, const char *filename, int module) +{ + uint8_t *buf; + int ret, eval_flags; + size_t buf_len; + + buf = js_load_file(ctx, &buf_len, filename); + if (!buf) { + perror(filename); + exit(1); + } + + if (module < 0) { + module = (js__has_suffix(filename, ".mjs") || + JS_DetectModule((const char *)buf, buf_len)); + } + if (module) + eval_flags = JS_EVAL_TYPE_MODULE; + else + eval_flags = JS_EVAL_TYPE_GLOBAL; + ret = eval_buf(ctx, buf, buf_len, filename, eval_flags); + js_free(ctx, buf); + return ret; +} + +static int64_t parse_limit(const char *arg) { + char *p; + unsigned long unit = 1024; /* default to traditional KB */ + double d = strtod(arg, &p); + + if (p == arg) { + fprintf(stderr, "Invalid limit: %s\n", arg); + return -1; + } + + if (*p) { + switch (*p++) { + case 'b': case 'B': unit = 1UL << 0; break; + case 'k': case 'K': unit = 1UL << 10; break; /* IEC kibibytes */ + case 'm': case 'M': unit = 1UL << 20; break; /* IEC mebibytes */ + case 'g': case 'G': unit = 1UL << 30; break; /* IEC gigibytes */ + default: + fprintf(stderr, "Invalid limit: %s, unrecognized suffix, only k,m,g are allowed\n", arg); + return -1; + } + if (*p) { + fprintf(stderr, "Invalid limit: %s, only one suffix allowed\n", arg); + return -1; + } + } + + return (int64_t)(d * unit); +} + +static JSValue js_gc(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JS_RunGC(JS_GetRuntime(ctx)); + return JS_UNDEFINED; +} + +static JSValue js_navigator_get_userAgent(JSContext *ctx, JSValueConst this_val) +{ + char version[32]; + snprintf(version, sizeof(version), "quickjs-ng/%s", JS_GetVersion()); + return JS_NewString(ctx, version); +} + +static const JSCFunctionListEntry navigator_proto_funcs[] = { + JS_CGETSET_DEF2("userAgent", js_navigator_get_userAgent, NULL, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Navigator", JS_PROP_CONFIGURABLE), +}; + +static const JSCFunctionListEntry global_obj[] = { + JS_CFUNC_DEF("gc", 0, js_gc), +}; + +/* also used to initialize the worker context */ +static JSContext *JS_NewCustomContext(JSRuntime *rt) +{ + JSContext *ctx; + ctx = JS_NewContext(rt); + if (!ctx) + return NULL; + /* system modules */ + js_init_module_std(ctx, "qjs:std"); + js_init_module_os(ctx, "qjs:os"); + js_init_module_bjson(ctx, "qjs:bjson"); + + JSValue global = JS_GetGlobalObject(ctx); + JS_SetPropertyFunctionList(ctx, global, global_obj, countof(global_obj)); + JSValue args = JS_NewArray(ctx); + int i; + for(i = 0; i < qjs__argc; i++) { + JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, qjs__argv[i])); + } + JS_SetPropertyStr(ctx, global, "execArgv", args); + JS_SetPropertyStr(ctx, global, "argv0", JS_NewString(ctx, qjs__argv[0])); + JSValue navigator_proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, navigator_proto, navigator_proto_funcs, countof(navigator_proto_funcs)); + JSValue navigator = JS_NewObjectProto(ctx, navigator_proto); + JS_DefinePropertyValueStr(ctx, global, "navigator", navigator, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE); + JS_FreeValue(ctx, global); + JS_FreeValue(ctx, navigator_proto); + + return ctx; +} + +struct trace_malloc_data { + uint8_t *base; +}; + +static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr, + struct trace_malloc_data *dp) +{ + return ptr - dp->base; +} + +static void JS_PRINTF_FORMAT_ATTR(2, 3) js_trace_malloc_printf(void *opaque, JS_PRINTF_FORMAT const char *fmt, ...) +{ + va_list ap; + int c; + + va_start(ap, fmt); + while ((c = *fmt++) != '\0') { + if (c == '%') { + /* only handle %p and %zd */ + if (*fmt == 'p') { + uint8_t *ptr = va_arg(ap, void *); + if (ptr == NULL) { + printf("NULL"); + } else { + printf("H%+06lld.%zd", + js_trace_malloc_ptr_offset(ptr, opaque), + js__malloc_usable_size(ptr)); + } + fmt++; + continue; + } + if (fmt[0] == 'z' && fmt[1] == 'd') { + size_t sz = va_arg(ap, size_t); + printf("%zd", sz); + fmt += 2; + continue; + } + } + putc(c, stdout); + } + va_end(ap); +} + +static void js_trace_malloc_init(struct trace_malloc_data *s) +{ + free(s->base = malloc(8)); +} + +static void *js_trace_calloc(void *opaque, size_t count, size_t size) +{ + void *ptr; + ptr = calloc(count, size); + js_trace_malloc_printf(opaque, "C %zd %zd -> %p\n", count, size, ptr); + return ptr; +} + +static void *js_trace_malloc(void *opaque, size_t size) +{ + void *ptr; + ptr = malloc(size); + js_trace_malloc_printf(opaque, "A %zd -> %p\n", size, ptr); + return ptr; +} + +static void js_trace_free(void *opaque, void *ptr) +{ + if (!ptr) + return; + js_trace_malloc_printf(opaque, "F %p\n", ptr); + free(ptr); +} + +static void *js_trace_realloc(void *opaque, void *ptr, size_t size) +{ + js_trace_malloc_printf(opaque, "R %zd %p", size, ptr); + ptr = realloc(ptr, size); + js_trace_malloc_printf(opaque, " -> %p\n", ptr); + return ptr; +} + +static const JSMallocFunctions trace_mf = { + js_trace_calloc, + js_trace_malloc, + js_trace_free, + js_trace_realloc, + js__malloc_usable_size +}; + +#ifdef QJS_USE_MIMALLOC +static void *js_mi_calloc(void *opaque, size_t count, size_t size) +{ + return mi_calloc(count, size); +} + +static void *js_mi_malloc(void *opaque, size_t size) +{ + return mi_malloc(size); +} + +static void js_mi_free(void *opaque, void *ptr) +{ + if (!ptr) + return; + mi_free(ptr); +} + +static void *js_mi_realloc(void *opaque, void *ptr, size_t size) +{ + return mi_realloc(ptr, size); +} + +static const JSMallocFunctions mi_mf = { + js_mi_calloc, + js_mi_malloc, + js_mi_free, + js_mi_realloc, + mi_malloc_usable_size +}; +#endif + +#define PROG_NAME "qjs" + +void help(void) +{ + printf("QuickJS-ng version %s\n" + "usage: " PROG_NAME " [options] [file [args]]\n" + "-h --help list options\n" + "-e --eval EXPR evaluate EXPR\n" + "-i --interactive go to interactive mode\n" + "-C --script load as JS classic script (default=autodetect)\n" + "-m --module load as ES module (default=autodetect)\n" + "-I --include file include an additional file\n" + " --std make 'std', 'os' and 'bjson' available to script\n" + "-T --trace trace memory allocation\n" + "-d --dump dump the memory usage stats\n" + "-D --dump-flags flags for dumping debug data (see DUMP_* defines)\n" + "-c --compile FILE compile the given JS file as a standalone executable\n" + "-o --out FILE output file for standalone executables\n" + " --exe select the executable to use as the base, defaults to the current one\n" + " --memory-limit n limit the memory usage to 'n' Kbytes\n" + " --stack-size n limit the stack size to 'n' Kbytes\n" + "-q --quit just instantiate the interpreter and quit\n", JS_GetVersion()); + exit(1); +} + +int main(int argc, char **argv) +{ + JSRuntime *rt; + JSContext *ctx; + JSValue ret = JS_UNDEFINED; + struct trace_malloc_data trace_data = { NULL }; + int r = 0; + int optind = 1; + char exebuf[JS__PATH_MAX]; + size_t exebuf_size = sizeof(exebuf); + char *compile_file = NULL; + char *exe = NULL; + char *expr = NULL; + char *dump_flags_str = NULL; + char *out = NULL; + int standalone = 0; + int interactive = 0; + int dump_memory = 0; + int dump_flags = 0; + int trace_memory = 0; + int empty_run = 0; + int module = -1; + int load_std = 0; + char *include_list[32]; + int i, include_count = 0; + int64_t memory_limit = -1; + int64_t stack_size = -1; + + /* save for later */ + qjs__argc = argc; + qjs__argv = argv; + + /* check if this is a standalone executable */ + + if (!js_exepath(exebuf, &exebuf_size) && is_standalone(exebuf)) { + standalone = 1; + goto start; + } + + dump_flags_str = getenv("QJS_DUMP_FLAGS"); + dump_flags = dump_flags_str ? strtol(dump_flags_str, NULL, 16) : 0; + + /* cannot use getopt because we want to pass the command line to + the script */ + while (optind < argc && *argv[optind] == '-') { + char *arg = argv[optind] + 1; + const char *longopt = ""; + char *optarg = NULL; + /* a single - is not an option, it also stops argument scanning */ + if (!*arg) + break; + optind++; + if (*arg == '-') { + longopt = arg + 1; + optarg = strchr(longopt, '='); + if (optarg) + *optarg++ = '\0'; + arg += strlen(arg); + /* -- stops argument scanning */ + if (!*longopt) + break; + } + for (; *arg || *longopt; longopt = "") { + char opt = *arg; + if (opt) { + arg++; + if (!optarg && *arg) + optarg = arg; + } + if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { + help(); + continue; + } + if (opt == 'e' || !strcmp(longopt, "eval")) { + if (!optarg) { + if (optind >= argc) { + fprintf(stderr, "qjs: missing expression for -e\n"); + exit(1); + } + optarg = argv[optind++]; + } + expr = optarg; + break; + } + if (opt == 'I' || !strcmp(longopt, "include")) { + if (optind >= argc) { + fprintf(stderr, "expecting filename"); + exit(1); + } + if (include_count >= countof(include_list)) { + fprintf(stderr, "too many included files"); + exit(1); + } + include_list[include_count++] = argv[optind++]; + continue; + } + if (opt == 'i' || !strcmp(longopt, "interactive")) { + interactive++; + continue; + } + if (opt == 'm' || !strcmp(longopt, "module")) { + module = 1; + continue; + } + if (opt == 'C' || !strcmp(longopt, "script")) { + module = 0; + continue; + } + if (opt == 'd' || !strcmp(longopt, "dump")) { + dump_memory++; + continue; + } + if (opt == 'D' || !strcmp(longopt, "dump-flags")) { + dump_flags = optarg ? strtol(optarg, NULL, 16) : 0; + break; + } + if (opt == 'T' || !strcmp(longopt, "trace")) { + trace_memory++; + continue; + } + if (!strcmp(longopt, "std")) { + load_std = 1; + continue; + } + if (opt == 'q' || !strcmp(longopt, "quit")) { + empty_run++; + continue; + } + if (!strcmp(longopt, "memory-limit")) { + if (!optarg) { + if (optind >= argc) { + fprintf(stderr, "expecting memory limit"); + exit(1); + } + optarg = argv[optind++]; + } + memory_limit = parse_limit(optarg); + break; + } + if (!strcmp(longopt, "stack-size")) { + if (!optarg) { + if (optind >= argc) { + fprintf(stderr, "expecting stack size"); + exit(1); + } + optarg = argv[optind++]; + } + stack_size = parse_limit(optarg); + break; + } + if (opt == 'c' || !strcmp(longopt, "compile")) { + if (!optarg) { + if (optind >= argc) { + fprintf(stderr, "qjs: missing file for -c\n"); + exit(1); + } + optarg = argv[optind++]; + } + compile_file = optarg; + break; + } + if (opt == 'o' || !strcmp(longopt, "out")) { + if (!optarg) { + if (optind >= argc) { + fprintf(stderr, "qjs: missing file for -o\n"); + exit(1); + } + optarg = argv[optind++]; + } + out = optarg; + break; + } + if (!strcmp(longopt, "exe")) { + if (!optarg) { + if (optind >= argc) { + fprintf(stderr, "qjs: missing file for --exe\n"); + exit(1); + } + optarg = argv[optind++]; + } + exe = optarg; + break; + } + if (opt) { + fprintf(stderr, "qjs: unknown option '-%c'\n", opt); + } else { + fprintf(stderr, "qjs: unknown option '--%s'\n", longopt); + } + help(); + } + } + + if (compile_file && !out) + help(); + +start: + + if (trace_memory) { + js_trace_malloc_init(&trace_data); + rt = JS_NewRuntime2(&trace_mf, &trace_data); + } else { +#ifdef QJS_USE_MIMALLOC + rt = JS_NewRuntime2(&mi_mf, NULL); +#else + rt = JS_NewRuntime(); +#endif + } + if (!rt) { + fprintf(stderr, "qjs: cannot allocate JS runtime\n"); + exit(2); + } + if (memory_limit >= 0) + JS_SetMemoryLimit(rt, (size_t)memory_limit); + if (stack_size >= 0) + JS_SetMaxStackSize(rt, (size_t)stack_size); + if (dump_flags != 0) + JS_SetDumpFlags(rt, dump_flags); + js_std_set_worker_new_context_func(JS_NewCustomContext); + js_std_init_handlers(rt); + ctx = JS_NewCustomContext(rt); + if (!ctx) { + fprintf(stderr, "qjs: cannot allocate JS context\n"); + exit(2); + } + + /* loader for ES6 modules */ + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); + + /* exit on unhandled promise rejections */ + JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, NULL); + + if (!empty_run) { + js_std_add_helpers(ctx, argc - optind, argv + optind); + + /* make 'std' and 'os' visible to non module code */ + if (load_std) { + const char *str = + "import * as bjson from 'qjs:bjson';\n" + "import * as std from 'qjs:std';\n" + "import * as os from 'qjs:os';\n" + "globalThis.bjson = bjson;\n" + "globalThis.std = std;\n" + "globalThis.os = os;\n"; + eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); + } + + for(i = 0; i < include_count; i++) { + if (eval_file(ctx, include_list[i], 0)) + goto fail; + } + + if (standalone) { + JSValue ns = load_standalone_module(ctx); + if (JS_IsException(ns)) + goto fail; + JSValue func = JS_GetPropertyStr(ctx, ns, "runStandalone"); + JS_FreeValue(ctx, ns); + if (JS_IsException(func)) + goto fail; + ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL); + JS_FreeValue(ctx, func); + } else if (compile_file) { + JSValue ns = load_standalone_module(ctx); + if (JS_IsException(ns)) + goto fail; + JSValue func = JS_GetPropertyStr(ctx, ns, "compileStandalone"); + JS_FreeValue(ctx, ns); + if (JS_IsException(func)) + goto fail; + JSValue args[3]; + args[0] = JS_NewString(ctx, compile_file); + args[1] = JS_NewString(ctx, out); + args[2] = exe != NULL ? JS_NewString(ctx, exe) : JS_UNDEFINED; + ret = JS_Call(ctx, func, JS_UNDEFINED, 3, (JSValueConst *)args); + JS_FreeValue(ctx, func); + JS_FreeValue(ctx, args[0]); + JS_FreeValue(ctx, args[1]); + JS_FreeValue(ctx, args[2]); + } else if (expr) { + int flags = module ? JS_EVAL_TYPE_MODULE : 0; + if (eval_buf(ctx, expr, strlen(expr), "", flags)) + goto fail; + } else if (optind >= argc) { + /* interactive mode */ + interactive = 1; + } else { + const char *filename; + filename = argv[optind]; + if (eval_file(ctx, filename, module)) + goto fail; + } + if (interactive) { + JS_SetHostPromiseRejectionTracker(rt, NULL, NULL); + js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0); + } + if (standalone || compile_file) { + if (JS_IsException(ret)) { + r = 1; + } else { + JS_FreeValue(ctx, ret); + r = js_std_loop(ctx); + } + } else { + r = js_std_loop(ctx); + } + if (r) { + js_std_dump_error(ctx); + goto fail; + } + } + + if (dump_memory) { + JSMemoryUsage stats; + JS_ComputeMemoryUsage(rt, &stats); + JS_DumpMemoryUsage(stdout, &stats, rt); + } + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + + if (empty_run && dump_memory) { + clock_t t[5]; + double best[5] = {0}; + int i, j; + for (i = 0; i < 100; i++) { + t[0] = clock(); + rt = JS_NewRuntime(); + t[1] = clock(); + ctx = JS_NewContext(rt); + t[2] = clock(); + JS_FreeContext(ctx); + t[3] = clock(); + JS_FreeRuntime(rt); + t[4] = clock(); + for (j = 4; j > 0; j--) { + double ms = 1000.0 * (t[j] - t[j - 1]) / CLOCKS_PER_SEC; + if (i == 0 || best[j] > ms) + best[j] = ms; + } + } + printf("\nInstantiation times (ms): %.3f = %.3f+%.3f+%.3f+%.3f\n", + best[1] + best[2] + best[3] + best[4], + best[1], best[2], best[3], best[4]); + } + return 0; + fail: + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return 1; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/qjsc.c b/host/cred-script/vendor/rquickjs-sys/quickjs/qjsc.c new file mode 100644 index 0000000..395bcb3 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/qjsc.c @@ -0,0 +1,673 @@ +/* + * QuickJS command line compiler + * + * Copyright (c) 2018-2024 Fabrice Bellard + * Copyright (c) 2023-2025 Ben Noordhuis + * Copyright (c) 2023-2025 Saúl Ibarra Corretgé + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "cutils.h" +#include "quickjs-libc.h" + +typedef enum { + OUTPUT_C, + OUTPUT_C_MAIN, + OUTPUT_RAW, +} OutputTypeEnum; + +typedef struct { + char *name; + char *short_name; + int flags; +} namelist_entry_t; + +typedef struct namelist_t { + namelist_entry_t *array; + int count; + int size; +} namelist_t; + +static namelist_t cname_list; +static namelist_t cmodule_list; +static namelist_t init_module_list; +static OutputTypeEnum output_type; +static FILE *outfile; +static const char *c_ident_prefix = "qjsc_"; +static int strip; + +void namelist_add(namelist_t *lp, const char *name, const char *short_name, + int flags) +{ + namelist_entry_t *e; + if (lp->count == lp->size) { + size_t newsize = lp->size + (lp->size >> 1) + 4; + namelist_entry_t *a = + realloc(lp->array, sizeof(lp->array[0]) * newsize); + /* XXX: check for realloc failure */ + lp->array = a; + lp->size = newsize; + } + e = &lp->array[lp->count++]; + e->name = strdup(name); + if (short_name) + e->short_name = strdup(short_name); + else + e->short_name = NULL; + e->flags = flags; +} + +void namelist_free(namelist_t *lp) +{ + while (lp->count > 0) { + namelist_entry_t *e = &lp->array[--lp->count]; + free(e->name); + free(e->short_name); + } + free(lp->array); + lp->array = NULL; + lp->size = 0; +} + +namelist_entry_t *namelist_find(namelist_t *lp, const char *name) +{ + int i; + for(i = 0; i < lp->count; i++) { + namelist_entry_t *e = &lp->array[i]; + if (!strcmp(e->name, name)) + return e; + } + return NULL; +} + +static void get_c_name(char *buf, size_t buf_size, const char *file) +{ + const char *p, *r; + size_t len, i; + int c; + char *q; + + p = strrchr(file, '/'); + if (!p) + p = file; + else + p++; + r = strrchr(p, '.'); + if (!r) + len = strlen(p); + else + len = r - p; + js__pstrcpy(buf, buf_size, c_ident_prefix); + q = buf + strlen(buf); + for(i = 0; i < len; i++) { + c = p[i]; + if (!((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z'))) { + c = '_'; + } + if ((q - buf) < buf_size - 1) + *q++ = c; + } + *q = '\0'; +} + +static void dump_hex(FILE *f, const uint8_t *buf, size_t len) +{ + size_t i, col; + col = 0; + for(i = 0; i < len; i++) { + fprintf(f, " 0x%02x,", buf[i]); + if (++col == 8) { + fprintf(f, "\n"); + col = 0; + } + } + if (col != 0) + fprintf(f, "\n"); +} + +static void output_object_code(JSContext *ctx, + FILE *fo, JSValue obj, const char *c_name, + bool load_only) +{ + uint8_t *out_buf; + size_t out_buf_len; + int flags = JS_WRITE_OBJ_BYTECODE; + + if (strip) { + flags |= JS_WRITE_OBJ_STRIP_SOURCE; + if (strip > 1) + flags |= JS_WRITE_OBJ_STRIP_DEBUG; + } + + out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags); + if (!out_buf) { + js_std_dump_error(ctx); + exit(1); + } + + namelist_add(&cname_list, c_name, NULL, load_only); + + if (output_type == OUTPUT_RAW) { + fwrite(out_buf, 1, out_buf_len, fo); + } else { + fprintf(fo, "const uint32_t %s_size = %u;\n\n", + c_name, (unsigned int)out_buf_len); + fprintf(fo, "const uint8_t %s[%u] = {\n", + c_name, (unsigned int)out_buf_len); + dump_hex(fo, out_buf, out_buf_len); + fprintf(fo, "};\n\n"); + } + + js_free(ctx, out_buf); +} + +static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m) +{ + /* should never be called when compiling JS code */ + abort(); + return -1; // pacify compiler +} + +static void find_unique_cname(char *cname, size_t cname_size) +{ + char cname1[1024]; + int suffix_num; + size_t len, max_len; + assert(cname_size >= 32); + /* find a C name not matching an existing module C name by + adding a numeric suffix */ + len = strlen(cname); + max_len = cname_size - 16; + if (len > max_len) + cname[max_len] = '\0'; + suffix_num = 1; + for(;;) { + snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num); + if (!namelist_find(&cname_list, cname1)) + break; + suffix_num++; + } + js__pstrcpy(cname, cname_size, cname1); +} + +JSModuleDef *jsc_module_loader(JSContext *ctx, + const char *module_name, void *opaque) +{ + JSModuleDef *m; + namelist_entry_t *e; + + /* check if it is a declared C or system module */ + e = namelist_find(&cmodule_list, module_name); + if (e) { + /* add in the static init module list */ + namelist_add(&init_module_list, e->name, e->short_name, 0); + /* create a dummy module */ + m = JS_NewCModule(ctx, module_name, js_module_dummy_init); + } else if (js__has_suffix(module_name, ".so")) { + JS_ThrowReferenceError(ctx, "%s: dynamically linking to shared libraries not supported", + module_name); + return NULL; + } else { + size_t buf_len; + uint8_t *buf; + JSValue func_val; + char cname[1000]; + + buf = js_load_file(ctx, &buf_len, module_name); + if (!buf) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", + module_name); + return NULL; + } + + /* compile the module */ + func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, + JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); + js_free(ctx, buf); + if (JS_IsException(func_val)) + return NULL; + get_c_name(cname, sizeof(cname), module_name); + if (namelist_find(&cname_list, cname)) { + find_unique_cname(cname, sizeof(cname)); + } + output_object_code(ctx, outfile, func_val, cname, true); + + /* the module is already referenced, so we must free it */ + m = JS_VALUE_GET_PTR(func_val); + JS_FreeValue(ctx, func_val); + } + return m; +} + +static void compile_file(JSContext *ctx, FILE *fo, + const char *filename, + const char *script_name, + const char *c_name1, + int module) +{ + uint8_t *buf; + char c_name[1024]; + int eval_flags; + JSValue obj; + size_t buf_len; + + buf = js_load_file(ctx, &buf_len, filename); + if (!buf) { + fprintf(stderr, "Could not load '%s'\n", filename); + exit(1); + } + eval_flags = JS_EVAL_FLAG_COMPILE_ONLY; + if (module < 0) { + module = (js__has_suffix(filename, ".mjs") || + JS_DetectModule((const char *)buf, buf_len)); + } + if (module) + eval_flags |= JS_EVAL_TYPE_MODULE; + else + eval_flags |= JS_EVAL_TYPE_GLOBAL; + obj = JS_Eval(ctx, (const char *)buf, buf_len, script_name ? script_name : filename, eval_flags); + if (JS_IsException(obj)) { + js_std_dump_error(ctx); + exit(1); + } + js_free(ctx, buf); + if (c_name1) { + js__pstrcpy(c_name, sizeof(c_name), c_name1); + } else { + get_c_name(c_name, sizeof(c_name), filename); + } + output_object_code(ctx, fo, obj, c_name, false); + JS_FreeValue(ctx, obj); +} + +static const char main_c_template1[] = + "int main(int argc, char **argv)\n" + "{\n" + " int r;\n" + " JSRuntime *rt;\n" + " JSContext *ctx;\n" + " r = 0;\n" + " rt = JS_NewRuntime();\n" + " js_std_set_worker_new_context_func(JS_NewCustomContext);\n" + " js_std_init_handlers(rt);\n" + ; + +static const char main_c_template2[] = + " r = js_std_loop(ctx);\n" + " if (r) {\n" + " js_std_dump_error(ctx);\n" + " }\n" + " js_std_free_handlers(rt);\n" + " JS_FreeContext(ctx);\n" + " JS_FreeRuntime(rt);\n" + " return r;\n" + "}\n"; + +#define PROG_NAME "qjsc" + +void help(void) +{ + printf("QuickJS-ng Compiler version %s\n" + "usage: " PROG_NAME " [options] [files]\n" + "\n" + "options are:\n" + "-b output raw bytecode instead of C code\n" + "-e output main() and bytecode in a C file\n" + "-o output set the output filename\n" + "-n script_name set the script name (as used in stack traces)\n" + "-N cname set the C name of the generated data\n" + "-C compile as JS classic script (default=autodetect)\n" + "-m compile as ES module (default=autodetect)\n" + "-D module_name compile a dynamically loaded module or worker\n" + "-M module_name[,cname] add initialization code for an external C module\n" + "-p prefix set the prefix of the generated C names\n" + "-P do not add default system modules\n" + "-s strip the source code, specify twice to also strip debug info\n" + "-S n set the maximum stack size to 'n' bytes (default=%d)\n", + JS_GetVersion(), + JS_DEFAULT_STACK_SIZE); + exit(1); +} + +// TODO(bnoordhuis) share with qjs.c maybe +static int64_t parse_limit(const char *arg) { + char *p; + unsigned long unit = 1; // bytes for backcompat; qjs defaults to kilobytes + double d = strtod(arg, &p); + + if (p == arg) { + fprintf(stderr, "qjsc: invalid limit: %s\n", arg); + return -1; + } + + if (*p) { + switch (*p++) { + case 'b': case 'B': unit = 1UL << 0; break; + case 'k': case 'K': unit = 1UL << 10; break; /* IEC kibibytes */ + case 'm': case 'M': unit = 1UL << 20; break; /* IEC mebibytes */ + case 'g': case 'G': unit = 1UL << 30; break; /* IEC gigibytes */ + default: + fprintf(stderr, "qjsc: invalid limit: %s, unrecognized suffix, only k,m,g are allowed\n", arg); + return -1; + } + if (*p) { + fprintf(stderr, "qjsc: invalid limit: %s, only one suffix allowed\n", arg); + return -1; + } + } + + return (int64_t)(d * unit); +} + +static void check_hasarg(int optind, int argc, int opt) +{ + if (optind >= argc) { + fprintf(stderr, "qjsc: missing file for -%c\n", opt); + exit(1); + } +} + +int main(int argc, char **argv) +{ + int optind = 1; + int i; + const char *out_filename, *cname, *script_name; + char cfilename[1024]; + FILE *fo; + JSRuntime *rt; + JSContext *ctx; + int module; + size_t stack_size; + namelist_t dynamic_module_list; + bool load_system_modules = true; + + out_filename = NULL; + script_name = NULL; + output_type = OUTPUT_C; + cname = NULL; + module = -1; + strip = 0; + stack_size = 0; + memset(&dynamic_module_list, 0, sizeof(dynamic_module_list)); + + + while (optind < argc && *argv[optind] == '-') { + char *arg = argv[optind] + 1; + const char *longopt = ""; + char *optarg = NULL; + /* a single - is not an option, it also stops argument scanning */ + if (!*arg) + break; + optind++; + if (*arg == '-') { + longopt = arg + 1; + optarg = strchr(longopt, '='); + if (optarg) + *optarg++ = '\0'; + arg += strlen(arg); + /* -- stops argument scanning */ + if (!*longopt) + break; + } + for (; *arg || *longopt; longopt = "") { + char opt = *arg; + if (opt) { + arg++; + if (!optarg && *arg) + optarg = arg; + } + if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { + help(); + continue; + } + if (opt == 'b') { + output_type = OUTPUT_RAW; + continue; + } + if (opt == 'o') { + if (!optarg) { + check_hasarg(optind, argc, opt); + optarg = argv[optind++]; + } + out_filename = optarg; + continue; + } + if (opt == 'e') { + output_type = OUTPUT_C_MAIN; + continue; + } + if (opt == 'n') { + if (!optarg) { + check_hasarg(optind, argc, opt); + optarg = argv[optind++]; + } + script_name = optarg; + continue; + } + if (opt == 'N') { + if (!optarg) { + check_hasarg(optind, argc, opt); + optarg = argv[optind++]; + } + cname = optarg; + continue; + } + if (opt == 'C') { + module = 0; + continue; + } + if (opt == 'm') { + module = 1; + continue; + } + if (opt == 'M') { + char *p; + char path[1024]; + char cname[1024]; + if (!optarg) { + check_hasarg(optind, argc, opt); + optarg = argv[optind++]; + } + js__pstrcpy(path, sizeof(path), optarg); + p = strchr(path, ','); + if (p) { + *p = '\0'; + js__pstrcpy(cname, sizeof(cname), p + 1); + } else { + get_c_name(cname, sizeof(cname), path); + } + namelist_add(&cmodule_list, path, cname, 0); + continue; + } + if (opt == 'D') { + if (!optarg) { + check_hasarg(optind, argc, opt); + optarg = argv[optind++]; + } + namelist_add(&dynamic_module_list, optarg, NULL, 0); + continue; + } + if (opt == 'P') { + load_system_modules = false; + continue; + } + if (opt == 's') { + strip++; + continue; + } + if (opt == 'p') { + if (!optarg) { + check_hasarg(optind, argc, opt); + optarg = argv[optind++]; + } + c_ident_prefix = optarg; + continue; + } + if (opt == 'S') { + if (!optarg) { + check_hasarg(optind, argc, opt); + optarg = argv[optind++]; + } + stack_size = parse_limit(optarg); + continue; + } + help(); + } + } + + if (load_system_modules) { + /* add system modules */ + namelist_add(&cmodule_list, "qjs:std", "std", 0); + namelist_add(&cmodule_list, "qjs:os", "os", 0); + namelist_add(&cmodule_list, "qjs:bjson", "bjson", 0); + namelist_add(&cmodule_list, "std", "std", 0); + namelist_add(&cmodule_list, "os", "os", 0); + namelist_add(&cmodule_list, "bjson", "bjson", 0); + } + + if (optind >= argc) + help(); + + if (!out_filename) + out_filename = "out.c"; + + js__pstrcpy(cfilename, sizeof(cfilename), out_filename); + + if (output_type == OUTPUT_RAW) + fo = fopen(cfilename, "wb"); + else + fo = fopen(cfilename, "w"); + + if (!fo) { + perror(cfilename); + exit(1); + } + outfile = fo; + + rt = JS_NewRuntime(); + ctx = JS_NewContext(rt); + + /* loader for ES6 modules */ + JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL); + + if (output_type != OUTPUT_RAW) { + fprintf(fo, "/* File generated automatically by the QuickJS-ng compiler. */\n" + "\n" + ); + } + + if (output_type == OUTPUT_C_MAIN) { + fprintf(fo, "#include \"quickjs-libc.h\"\n" + "\n" + ); + } else if (output_type == OUTPUT_C) { + fprintf(fo, "#include \n" + "\n" + ); + } + + for(i = optind; i < argc; i++) { + const char *filename = argv[i]; + compile_file(ctx, fo, filename, script_name, cname, module); + cname = NULL; + } + + for(i = 0; i < dynamic_module_list.count; i++) { + if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) { + fprintf(stderr, "Could not load dynamic module '%s'\n", + dynamic_module_list.array[i].name); + exit(1); + } + } + + if (output_type == OUTPUT_C_MAIN) { + fprintf(fo, + "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n" + "{\n" + " JSContext *ctx = JS_NewContext(rt);\n" + " if (!ctx)\n" + " return NULL;\n"); + /* add the precompiled modules (XXX: could modify the module + loader instead) */ + for(i = 0; i < init_module_list.count; i++) { + namelist_entry_t *e = &init_module_list.array[i]; + /* initialize the static C modules */ + + fprintf(fo, + " {\n" + " extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n" + " js_init_module_%s(ctx, \"%s\");\n" + " }\n", + e->short_name, e->short_name, e->name); + } + for(i = 0; i < cname_list.count; i++) { + namelist_entry_t *e = &cname_list.array[i]; + if (e->flags) { + fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n", + e->name, e->name); + } + } + fprintf(fo, + " return ctx;\n" + "}\n\n"); + + fputs(main_c_template1, fo); + + if (stack_size != 0) { + fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n", + (unsigned int)stack_size); + } + + /* add the module loader */ + fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n"); + + fprintf(fo, + " ctx = JS_NewCustomContext(rt);\n" + " js_std_add_helpers(ctx, argc, argv);\n"); + + for(i = 0; i < cname_list.count; i++) { + namelist_entry_t *e = &cname_list.array[i]; + if (!e->flags) { + fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n", + e->name, e->name); + } + } + fputs(main_c_template2, fo); + } + + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + + fclose(fo); + + namelist_free(&cname_list); + namelist_free(&cmodule_list); + namelist_free(&init_module_list); + return 0; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-atom.h b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-atom.h new file mode 100644 index 0000000..2a12328 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-atom.h @@ -0,0 +1,265 @@ +/* + * QuickJS atom definitions + * + * Copyright (c) 2017-2018 Fabrice Bellard + * Copyright (c) 2017-2018 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifdef DEF + +/* Note: first atoms are considered as keywords in the parser */ +DEF(null, "null") /* must be first */ +DEF(false, "false") +DEF(true, "true") +DEF(if, "if") +DEF(else, "else") +DEF(return, "return") +DEF(var, "var") +DEF(this, "this") +DEF(delete, "delete") +DEF(void, "void") +DEF(typeof, "typeof") +DEF(new, "new") +DEF(in, "in") +DEF(instanceof, "instanceof") +DEF(do, "do") +DEF(while, "while") +DEF(for, "for") +DEF(break, "break") +DEF(continue, "continue") +DEF(switch, "switch") +DEF(case, "case") +DEF(default, "default") +DEF(throw, "throw") +DEF(try, "try") +DEF(catch, "catch") +DEF(finally, "finally") +DEF(function, "function") +DEF(debugger, "debugger") +DEF(with, "with") +/* FutureReservedWord */ +DEF(class, "class") +DEF(const, "const") +DEF(enum, "enum") +DEF(export, "export") +DEF(extends, "extends") +DEF(import, "import") +DEF(super, "super") +/* FutureReservedWords when parsing strict mode code */ +DEF(implements, "implements") +DEF(interface, "interface") +DEF(let, "let") +DEF(package, "package") +DEF(private, "private") +DEF(protected, "protected") +DEF(public, "public") +DEF(static, "static") +DEF(yield, "yield") +DEF(await, "await") + +/* empty string */ +DEF(empty_string, "") +/* identifiers */ +DEF(keys, "keys") +DEF(size, "size") +DEF(length, "length") +DEF(message, "message") +DEF(cause, "cause") +DEF(errors, "errors") +DEF(stack, "stack") +DEF(name, "name") +DEF(toString, "toString") +DEF(toLocaleString, "toLocaleString") +DEF(valueOf, "valueOf") +DEF(eval, "eval") +DEF(prototype, "prototype") +DEF(constructor, "constructor") +DEF(configurable, "configurable") +DEF(writable, "writable") +DEF(enumerable, "enumerable") +DEF(value, "value") +DEF(get, "get") +DEF(set, "set") +DEF(of, "of") +DEF(__proto__, "__proto__") +DEF(undefined, "undefined") +DEF(number, "number") +DEF(boolean, "boolean") +DEF(string, "string") +DEF(object, "object") +DEF(symbol, "symbol") +DEF(integer, "integer") +DEF(unknown, "unknown") +DEF(arguments, "arguments") +DEF(callee, "callee") +DEF(caller, "caller") +DEF(_eval_, "") +DEF(_ret_, "") +DEF(_var_, "") +DEF(_arg_var_, "") +DEF(_with_, "") +DEF(lastIndex, "lastIndex") +DEF(target, "target") +DEF(index, "index") +DEF(input, "input") +DEF(defineProperties, "defineProperties") +DEF(apply, "apply") +DEF(join, "join") +DEF(concat, "concat") +DEF(split, "split") +DEF(construct, "construct") +DEF(getPrototypeOf, "getPrototypeOf") +DEF(setPrototypeOf, "setPrototypeOf") +DEF(isExtensible, "isExtensible") +DEF(preventExtensions, "preventExtensions") +DEF(has, "has") +DEF(deleteProperty, "deleteProperty") +DEF(defineProperty, "defineProperty") +DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor") +DEF(ownKeys, "ownKeys") +DEF(add, "add") +DEF(done, "done") +DEF(next, "next") +DEF(values, "values") +DEF(source, "source") +DEF(flags, "flags") +DEF(global, "global") +DEF(unicode, "unicode") +DEF(raw, "raw") +DEF(new_target, "new.target") +DEF(this_active_func, "this.active_func") +DEF(home_object, "") +DEF(computed_field, "") +DEF(static_computed_field, "") /* must come after computed_fields */ +DEF(class_fields_init, "") +DEF(brand, "") +DEF(hash_constructor, "#constructor") +DEF(as, "as") +DEF(from, "from") +DEF(fromAsync, "fromAsync") +DEF(meta, "meta") +DEF(_default_, "*default*") +DEF(_star_, "*") +DEF(Module, "Module") +DEF(then, "then") +DEF(resolve, "resolve") +DEF(reject, "reject") +DEF(promise, "promise") +DEF(proxy, "proxy") +DEF(revoke, "revoke") +DEF(async, "async") +DEF(exec, "exec") +DEF(groups, "groups") +DEF(indices, "indices") +DEF(status, "status") +DEF(reason, "reason") +DEF(globalThis, "globalThis") +DEF(bigint, "bigint") +DEF(not_equal, "not-equal") +DEF(timed_out, "timed-out") +DEF(ok, "ok") +DEF(toJSON, "toJSON") +DEF(maxByteLength, "maxByteLength") +/* class names */ +DEF(Object, "Object") +DEF(Array, "Array") +DEF(Error, "Error") +DEF(Number, "Number") +DEF(String, "String") +DEF(Boolean, "Boolean") +DEF(Symbol, "Symbol") +DEF(Arguments, "Arguments") +DEF(Math, "Math") +DEF(JSON, "JSON") +DEF(Date, "Date") +DEF(Function, "Function") +DEF(GeneratorFunction, "GeneratorFunction") +DEF(ForInIterator, "ForInIterator") +DEF(RegExp, "RegExp") +DEF(ArrayBuffer, "ArrayBuffer") +DEF(SharedArrayBuffer, "SharedArrayBuffer") +/* must keep same order as class IDs for typed arrays */ +DEF(Uint8ClampedArray, "Uint8ClampedArray") +DEF(Int8Array, "Int8Array") +DEF(Uint8Array, "Uint8Array") +DEF(Int16Array, "Int16Array") +DEF(Uint16Array, "Uint16Array") +DEF(Int32Array, "Int32Array") +DEF(Uint32Array, "Uint32Array") +DEF(BigInt64Array, "BigInt64Array") +DEF(BigUint64Array, "BigUint64Array") +DEF(Float16Array, "Float16Array") +DEF(Float32Array, "Float32Array") +DEF(Float64Array, "Float64Array") +DEF(DataView, "DataView") +DEF(BigInt, "BigInt") +DEF(WeakRef, "WeakRef") +DEF(FinalizationRegistry, "FinalizationRegistry") +DEF(Map, "Map") +DEF(Set, "Set") /* Map + 1 */ +DEF(WeakMap, "WeakMap") /* Map + 2 */ +DEF(WeakSet, "WeakSet") /* Map + 3 */ +DEF(Iterator, "Iterator") +DEF(IteratorConcat, "Iterator Concat") +DEF(IteratorHelper, "Iterator Helper") +DEF(IteratorWrap, "Iterator Wrap") +DEF(Map_Iterator, "Map Iterator") +DEF(Set_Iterator, "Set Iterator") +DEF(Array_Iterator, "Array Iterator") +DEF(String_Iterator, "String Iterator") +DEF(RegExp_String_Iterator, "RegExp String Iterator") +DEF(Generator, "Generator") +DEF(Proxy, "Proxy") +DEF(Promise, "Promise") +DEF(PromiseResolveFunction, "PromiseResolveFunction") +DEF(PromiseRejectFunction, "PromiseRejectFunction") +DEF(AsyncFunction, "AsyncFunction") +DEF(AsyncFunctionResolve, "AsyncFunctionResolve") +DEF(AsyncFunctionReject, "AsyncFunctionReject") +DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction") +DEF(AsyncGenerator, "AsyncGenerator") +DEF(EvalError, "EvalError") +DEF(RangeError, "RangeError") +DEF(ReferenceError, "ReferenceError") +DEF(SyntaxError, "SyntaxError") +DEF(TypeError, "TypeError") +DEF(URIError, "URIError") +DEF(InternalError, "InternalError") +DEF(DOMException, "DOMException") +DEF(CallSite, "CallSite") +/* private symbols */ +DEF(Private_brand, "") +/* symbols */ +DEF(Symbol_toPrimitive, "Symbol.toPrimitive") +DEF(Symbol_iterator, "Symbol.iterator") +DEF(Symbol_match, "Symbol.match") +DEF(Symbol_matchAll, "Symbol.matchAll") +DEF(Symbol_replace, "Symbol.replace") +DEF(Symbol_search, "Symbol.search") +DEF(Symbol_split, "Symbol.split") +DEF(Symbol_toStringTag, "Symbol.toStringTag") +DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") +DEF(Symbol_hasInstance, "Symbol.hasInstance") +DEF(Symbol_species, "Symbol.species") +DEF(Symbol_unscopables, "Symbol.unscopables") +DEF(Symbol_asyncIterator, "Symbol.asyncIterator") + +#endif /* DEF */ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-c-atomics.h b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-c-atomics.h new file mode 100644 index 0000000..8fc6b72 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-c-atomics.h @@ -0,0 +1,54 @@ +/* + * QuickJS C atomics definitions + * + * Copyright (c) 2023 Marcin Kolny + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) + // Use GCC builtins for version < 4.9 +# if((__GNUC__ << 16) + __GNUC_MINOR__ < ((4) << 16) + 9) +# define GCC_BUILTIN_ATOMICS +# endif +#endif + +#ifdef GCC_BUILTIN_ATOMICS +#define atomic_fetch_add(obj, arg) \ + __atomic_fetch_add(obj, arg, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong(obj, expected, desired) \ + __atomic_compare_exchange_n(obj, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_exchange(obj, desired) \ + __atomic_exchange_n (obj, desired, __ATOMIC_SEQ_CST) +#define atomic_load(obj) \ + __atomic_load_n(obj, __ATOMIC_SEQ_CST) +#define atomic_store(obj, desired) \ + __atomic_store_n(obj, desired, __ATOMIC_SEQ_CST) +#define atomic_fetch_or(obj, arg) \ + __atomic_fetch_or(obj, arg, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor(obj, arg) \ + __atomic_fetch_xor(obj, arg, __ATOMIC_SEQ_CST) +#define atomic_fetch_and(obj, arg) \ + __atomic_fetch_and(obj, arg, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub(obj, arg) \ + __atomic_fetch_sub(obj, arg, __ATOMIC_SEQ_CST) +#define _Atomic +#else +#include +#endif diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-libc.c b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-libc.c new file mode 100644 index 0000000..ae01300 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-libc.c @@ -0,0 +1,4693 @@ +/* + * QuickJS C library + * + * Copyright (c) 2017-2021 Fabrice Bellard + * Copyright (c) 2017-2021 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "quickjs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(_MSC_VER) +#include +#include +#endif +#include +#include +#include +#include +#if !defined(_MSC_VER) +#include +#endif +#if defined(_WIN32) +#include +#include +#include +#include +#include +#include +#include +#define popen _popen +#define pclose _pclose +#define rmdir _rmdir +#define getcwd _getcwd +#define chdir _chdir +#else +#include +#include +#if !defined(__wasi__) +#include +#include +#include +#include +#include +#endif + +#if defined(__APPLE__) +typedef sig_t sighandler_t; +#include +#include +#define environ (*_NSGetEnviron()) +#endif + +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) +typedef sig_t sighandler_t; +extern char **environ; +#endif + +#endif /* _WIN32 */ + +#include "cutils.h" +#include "list.h" +#include "quickjs-libc.h" + +#if JS_HAVE_THREADS +#include "quickjs-c-atomics.h" +#define USE_WORKER // enable os.Worker +#endif + +#ifndef S_IFBLK +#define S_IFBLK 0 +#endif + +#ifndef S_IFIFO +#define S_IFIFO 0 +#endif + +#ifndef MAX_SAFE_INTEGER // already defined in amalgamation builds +#define MAX_SAFE_INTEGER (((int64_t) 1 << 53) - 1) +#endif + +#ifndef QJS_NATIVE_MODULE_SUFFIX +#ifdef _WIN32 +#define QJS_NATIVE_MODULE_SUFFIX ".dll" +#else +#define QJS_NATIVE_MODULE_SUFFIX ".so" +#endif +#endif + +/* TODO: + - add socket calls +*/ + +typedef struct { + struct list_head link; + int fd; + JSValue rw_func[2]; +} JSOSRWHandler; + +typedef struct { + struct list_head link; + int sig_num; + JSValue func; +} JSOSSignalHandler; + +typedef struct { + struct list_head link; + int64_t timer_id; + uint8_t repeats:1; + int64_t timeout; + int64_t delay; + JSValue func; +} JSOSTimer; + +typedef struct { + struct list_head link; + JSValue promise; + JSValue reason; +} JSRejectedPromiseEntry; + +#ifdef USE_WORKER + +typedef struct { + struct list_head link; + uint8_t *data; + size_t data_len; + /* list of SharedArrayBuffers, necessary to free the message */ + uint8_t **sab_tab; + size_t sab_tab_len; +} JSWorkerMessage; + +typedef struct JSWaker { +#ifdef _WIN32 + HANDLE handle; +#else + int read_fd; + int write_fd; +#endif +} JSWaker; + +typedef struct { + int ref_count; + js_mutex_t mutex; + struct list_head msg_queue; /* list of JSWorkerMessage.link */ + JSWaker waker; +} JSWorkerMessagePipe; + +typedef struct { + struct list_head link; + JSWorkerMessagePipe *recv_pipe; + JSValue on_message_func; +} JSWorkerMessageHandler; + +#endif // USE_WORKER + +typedef struct JSThreadState { + struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */ + struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */ + struct list_head os_timers; /* list of JSOSTimer.link */ + struct list_head port_list; /* list of JSWorkerMessageHandler.link */ + struct list_head rejected_promise_list; /* list of JSRejectedPromiseEntry.link */ + int eval_script_recurse; /* only used in the main thread */ + int64_t next_timer_id; /* for setTimeout / setInterval */ + bool can_js_os_poll; + /* not used in the main thread */ +#ifdef USE_WORKER + JSWorkerMessagePipe *recv_pipe, *send_pipe; +#else + void *recv_pipe; +#endif // USE_WORKER + JSClassID std_file_class_id; + JSClassID worker_class_id; +} JSThreadState; + +static uint64_t os_pending_signals; + +static void *js_std_dbuf_realloc(void *opaque, void *ptr, size_t size) +{ + JSRuntime *rt = opaque; + return js_realloc_rt(rt, ptr, size); +} + +static void js_std_dbuf_init(JSContext *ctx, DynBuf *s) +{ + dbuf_init2(s, JS_GetRuntime(ctx), js_std_dbuf_realloc); +} + +static bool my_isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} + +static JSThreadState *js_get_thread_state(JSRuntime *rt) +{ + return (JSThreadState *)js_std_cmd(/*GetOpaque*/0, rt); +} + +static void js_set_thread_state(JSRuntime *rt, JSThreadState *ts) +{ + js_std_cmd(/*SetOpaque*/1, rt, ts); +} + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif // __GNUC__ +static JSValue js_printf_internal(JSContext *ctx, + int argc, JSValueConst *argv, FILE *fp) +{ + char fmtbuf[32]; + uint8_t cbuf[UTF8_CHAR_LEN_MAX+1]; + JSValue res; + DynBuf dbuf; + const char *fmt_str = NULL; + const uint8_t *fmt, *fmt_end; + const uint8_t *p; + char *q; + int i, c, len, mod; + size_t fmt_len; + int32_t int32_arg; + int64_t int64_arg; + double double_arg; + const char *string_arg; + + js_std_dbuf_init(ctx, &dbuf); + + if (argc > 0) { + fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]); + if (!fmt_str) + goto fail; + + i = 1; + fmt = (const uint8_t *)fmt_str; + fmt_end = fmt + fmt_len; + while (fmt < fmt_end) { + for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++) + continue; + dbuf_put(&dbuf, p, fmt - p); + if (fmt >= fmt_end) + break; + q = fmtbuf; + *q++ = *fmt++; /* copy '%' */ + + /* flags */ + for(;;) { + c = *fmt; + if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' || + c == '\'') { + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = c; + fmt++; + } else { + break; + } + } + /* width */ + if (*fmt == '*') { + if (i >= argc) + goto missing; + if (JS_ToInt32(ctx, &int32_arg, argv[i++])) + goto fail; + q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg); + fmt++; + } else { + while (my_isdigit(*fmt)) { + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = *fmt++; + } + } + if (*fmt == '.') { + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = *fmt++; + if (*fmt == '*') { + if (i >= argc) + goto missing; + if (JS_ToInt32(ctx, &int32_arg, argv[i++])) + goto fail; + q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg); + fmt++; + } else { + while (my_isdigit(*fmt)) { + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = *fmt++; + } + } + } + + /* we only support the "l" modifier for 64 bit numbers */ + mod = ' '; + if (*fmt == 'l') { + mod = *fmt++; + } + + /* type */ + c = *fmt++; + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = c; + *q = '\0'; + + switch (c) { + case 'c': + if (i >= argc) + goto missing; + if (JS_IsString(argv[i])) { + // TODO(chqrlie) need an API to wrap charCodeAt and codePointAt */ + string_arg = JS_ToCString(ctx, argv[i++]); + if (!string_arg) + goto fail; + int32_arg = utf8_decode((const uint8_t *)string_arg, &p); + JS_FreeCString(ctx, string_arg); + } else { + if (JS_ToInt32(ctx, &int32_arg, argv[i++])) + goto fail; + } + // XXX: throw an exception? + if ((unsigned)int32_arg > 0x10FFFF) + int32_arg = 0xFFFD; + /* ignore conversion flags, width and precision */ + len = utf8_encode(cbuf, int32_arg); + dbuf_put(&dbuf, cbuf, len); + break; + + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (i >= argc) + goto missing; + if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++])) + goto fail; + if (mod == 'l') { + /* 64 bit number */ +#if defined(_WIN32) + if (q >= fmtbuf + sizeof(fmtbuf) - 3) + goto invalid; + q[2] = q[-1]; + q[-1] = 'I'; + q[0] = '6'; + q[1] = '4'; + q[3] = '\0'; + dbuf_printf(&dbuf, fmtbuf, (int64_t)int64_arg); +#else + if (q >= fmtbuf + sizeof(fmtbuf) - 2) + goto invalid; + q[1] = q[-1]; + q[-1] = q[0] = 'l'; + q[2] = '\0'; + dbuf_printf(&dbuf, fmtbuf, (long long)int64_arg); +#endif + } else { + dbuf_printf(&dbuf, fmtbuf, (int)int64_arg); + } + break; + + case 's': + if (i >= argc) + goto missing; + /* XXX: handle strings containing null characters */ + string_arg = JS_ToCString(ctx, argv[i++]); + if (!string_arg) + goto fail; + dbuf_printf(&dbuf, fmtbuf, string_arg); + JS_FreeCString(ctx, string_arg); + break; + + case 'e': + case 'f': + case 'g': + case 'a': + case 'E': + case 'F': + case 'G': + case 'A': + if (i >= argc) + goto missing; + if (JS_ToFloat64(ctx, &double_arg, argv[i++])) + goto fail; + dbuf_printf(&dbuf, fmtbuf, double_arg); + break; + + case '%': + dbuf_putc(&dbuf, '%'); + break; + + default: + /* XXX: should support an extension mechanism */ + invalid: + JS_ThrowTypeError(ctx, "invalid conversion specifier in format string"); + goto fail; + missing: + JS_ThrowReferenceError(ctx, "missing argument for conversion specifier"); + goto fail; + } + } + JS_FreeCString(ctx, fmt_str); + } + if (dbuf.error) { + res = JS_ThrowOutOfMemory(ctx); + } else { + if (fp) { + len = fwrite(dbuf.buf, 1, dbuf.size, fp); + res = JS_NewInt32(ctx, len); + } else { + res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size); + } + } + dbuf_free(&dbuf); + return res; + +fail: + JS_FreeCString(ctx, fmt_str); + dbuf_free(&dbuf); + return JS_EXCEPTION; +} +#ifdef __GNUC__ +#pragma GCC diagnostic pop // ignored "-Wformat-nonliteral" +#endif // __GNUC__ + +uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename) +{ + FILE *f; + size_t n, len; + uint8_t *p, *buf, tmp[8192]; + + f = fopen(filename, "rb"); + if (!f) + return NULL; + buf = NULL; + len = 0; + do { + n = fread(tmp, 1, sizeof(tmp), f); + if (ctx) { + p = js_realloc(ctx, buf, len + n + 1); + } else { + p = realloc(buf, len + n + 1); + } + if (!p) { + if (ctx) { + js_free(ctx, buf); + } else { + free(buf); + } + fclose(f); + return NULL; + } + memcpy(&p[len], tmp, n); + buf = p; + len += n; + buf[len] = '\0'; + } while (n == sizeof(tmp)); + fclose(f); + *pbuf_len = len; + return buf; +} + +/* load and evaluate a file */ +static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + uint8_t *buf; + const char *filename; + JSValue ret; + size_t buf_len; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + return JS_EXCEPTION; + buf = js_load_file(ctx, &buf_len, filename); + if (!buf) { + JS_ThrowReferenceError(ctx, "could not load '%s'", filename); + JS_FreeCString(ctx, filename); + return JS_EXCEPTION; + } + ret = JS_Eval(ctx, (char *)buf, buf_len, filename, + JS_EVAL_TYPE_GLOBAL); + js_free(ctx, buf); + JS_FreeCString(ctx, filename); + return ret; +} + +static int get_bool_option(JSContext *ctx, bool *pbool, + JSValueConst obj, + const char *option) +{ + JSValue val; + val = JS_GetPropertyStr(ctx, obj, option); + if (JS_IsException(val)) + return -1; + if (!JS_IsUndefined(val)) { + *pbool = JS_ToBool(ctx, val); + } + JS_FreeValue(ctx, val); + return 0; +} + +static void free_buf(JSRuntime *rt, void *opaque, void *ptr) { + js_free_rt(rt, ptr); +} + +/* load a file as a UTF-8 encoded string or Uint8Array */ +static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + uint8_t *buf; + const char *filename; + JSValueConst options_obj; + JSValue ret; + size_t buf_len; + bool binary = false; + + if (argc >= 2) { + options_obj = argv[1]; + if (get_bool_option(ctx, &binary, options_obj, + "binary")) + return JS_EXCEPTION; + } + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + return JS_EXCEPTION; + buf = js_load_file(ctx, &buf_len, filename); + JS_FreeCString(ctx, filename); + if (!buf) + return JS_NULL; + if (binary) { + ret = JS_NewUint8Array(ctx, buf, buf_len, free_buf, NULL, false); + } else { + ret = JS_NewStringLen(ctx, (char *)buf, buf_len); + js_free(ctx, buf); + } + + return ret; +} + +static JSValue js_std_writeFile(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *filename; + const char *mode; + const void *buf; + size_t len, n; + JSValueConst data; + JSValue val, ret, unref; + bool release; + FILE *fp; + + ret = JS_EXCEPTION; + len = 0; + buf = ""; + mode = "w"; + data = argv[1]; + unref = JS_UNDEFINED; + release = false; + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + return JS_EXCEPTION; + if (JS_IsObject(data)) { + val = JS_GetPropertyStr(ctx, data, "buffer"); + if (JS_IsException(val)) + goto exception; + if (JS_IsArrayBuffer(val)) { + data = unref = val; + } else { + JS_FreeValue(ctx, val); + } + } + if (JS_IsArrayBuffer(data)) { + buf = JS_GetArrayBuffer(ctx, &len, data); + mode = "wb"; + } else if (!JS_IsUndefined(data)) { + buf = JS_ToCStringLen(ctx, &len, data); + release = true; + } + if (!buf) + goto exception; + fp = fopen(filename, mode); + if (!fp) { + JS_ThrowPlainError(ctx, "error opening %s for writing", filename); + goto exception; + } + n = fwrite(buf, len, 1, fp); + fclose(fp); + if (n != 1) { + JS_ThrowPlainError(ctx, "error writing to %s", filename); + goto exception; + } + ret = JS_UNDEFINED; +exception: + JS_FreeCString(ctx, filename); + if (release) + JS_FreeCString(ctx, buf); + JS_FreeValue(ctx, unref); + return ret; +} + +typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx, + const char *module_name); + + +#if defined(_WIN32) +static JSModuleDef *js_module_loader_so(JSContext *ctx, + const char *module_name) +{ + JSModuleDef *m; + HINSTANCE hd; + JSInitModuleFunc *init; + char *filename = NULL; + size_t len = strlen(module_name); + bool is_absolute = len > 2 && ((module_name[0] >= 'A' && module_name[0] <= 'Z') || + (module_name[0] >= 'a' && module_name[0] <= 'z')) && module_name[1] == ':'; + bool is_relative = len > 2 && module_name[0] == '.' && (module_name[1] == '/' || module_name[1] == '\\'); + if (is_absolute || is_relative) { + filename = (char *)module_name; + } else { + filename = js_malloc(ctx, len + 2 + 1); + if (!filename) + return NULL; + strcpy(filename, "./"); + strcpy(filename + 2, module_name); + } + hd = LoadLibraryA(filename); + if (filename != module_name) + js_free(ctx, filename); + if (hd == NULL) { + JS_ThrowReferenceError(ctx, "js_load_module '%s' error: %lu", + module_name, GetLastError()); + goto fail; + } + init = (JSInitModuleFunc *)(uintptr_t)GetProcAddress(hd, "js_init_module"); + if (!init) { + JS_ThrowReferenceError(ctx, "js_init_module '%s' not found: %lu", + module_name, GetLastError()); + goto fail; + } + m = init(ctx, module_name); + if (!m) { + JS_ThrowReferenceError(ctx, "js_call_module '%s' initialization error", + module_name); + fail: + if (hd != NULL) + FreeLibrary(hd); + return NULL; + } + return m; +} +#elif defined(__wasi__) +static JSModuleDef *js_module_loader_so(JSContext *ctx, + const char *module_name) +{ + JS_ThrowReferenceError(ctx, "shared library modules are not supported yet"); + return NULL; +} +#else +static JSModuleDef *js_module_loader_so(JSContext *ctx, + const char *module_name) +{ + JSModuleDef *m; + void *hd; + JSInitModuleFunc *init; + char *filename; + + if (!strchr(module_name, '/')) { + /* must add a '/' so that the DLL is not searched in the + system library paths */ + filename = js_malloc(ctx, strlen(module_name) + 2 + 1); + if (!filename) + return NULL; + strcpy(filename, "./"); + strcpy(filename + 2, module_name); + } else { + filename = (char *)module_name; + } + + /* C module */ + hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL); + if (filename != module_name) + js_free(ctx, filename); + if (!hd) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library: %s", + module_name, dlerror()); + goto fail; + } + + *(void **) (&init) = dlsym(hd, "js_init_module"); + if (!init) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s': js_init_module not found", + module_name); + goto fail; + } + + m = init(ctx, module_name); + if (!m) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s': initialization error", + module_name); + fail: + if (hd) + dlclose(hd); + return NULL; + } + return m; +} +#endif /* !_WIN32 */ + +int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, + bool use_realpath, bool is_main) +{ + JSModuleDef *m; + char buf[JS__PATH_MAX + 16]; + JSValue meta_obj; + JSAtom module_name_atom; + const char *module_name; + + assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE); + m = JS_VALUE_GET_PTR(func_val); + + module_name_atom = JS_GetModuleName(ctx, m); + module_name = JS_AtomToCString(ctx, module_name_atom); + JS_FreeAtom(ctx, module_name_atom); + if (!module_name) + return -1; + if (!strchr(module_name, ':')) { + strcpy(buf, "file://"); +#if !defined(_WIN32) && !defined(__wasi__) + /* realpath() cannot be used with modules compiled with qjsc + because the corresponding module source code is not + necessarily present */ + if (use_realpath) { + char *res = realpath(module_name, buf + strlen(buf)); + if (!res) { + JS_ThrowTypeError(ctx, "realpath failure"); + JS_FreeCString(ctx, module_name); + return -1; + } + } else +#endif + { + js__pstrcat(buf, sizeof(buf), module_name); + } + } else { + js__pstrcpy(buf, sizeof(buf), module_name); + } + JS_FreeCString(ctx, module_name); + + meta_obj = JS_GetImportMeta(ctx, m); + if (JS_IsException(meta_obj)) + return -1; + JS_DefinePropertyValueStr(ctx, meta_obj, "url", + JS_NewString(ctx, buf), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, meta_obj, "main", + JS_NewBool(ctx, is_main), + JS_PROP_C_W_E); + JS_FreeValue(ctx, meta_obj); + return 0; +} + +JSModuleDef *js_module_loader(JSContext *ctx, + const char *module_name, void *opaque) +{ + JSModuleDef *m; + + if (js__has_suffix(module_name, QJS_NATIVE_MODULE_SUFFIX)) { + m = js_module_loader_so(ctx, module_name); + } else { + size_t buf_len; + uint8_t *buf; + JSValue func_val; + + buf = js_load_file(ctx, &buf_len, module_name); + if (!buf) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", + module_name); + return NULL; + } + + /* compile the module */ + func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, + JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); + js_free(ctx, buf); + if (JS_IsException(func_val)) + return NULL; + if (js_module_set_import_meta(ctx, func_val, true, false) < 0) { + JS_FreeValue(ctx, func_val); + return NULL; + } + /* the module is already referenced, so we must free it */ + m = JS_VALUE_GET_PTR(func_val); + JS_FreeValue(ctx, func_val); + } + return m; +} + +static JSValue js_std_exit(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int status; + if (JS_ToInt32(ctx, &status, argv[0])) + status = -1; + exit(status); + return JS_UNDEFINED; +} + +static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *name, *str; + name = JS_ToCString(ctx, argv[0]); + if (!name) + return JS_EXCEPTION; + str = getenv(name); + JS_FreeCString(ctx, name); + if (!str) + return JS_UNDEFINED; + else + return JS_NewString(ctx, str); +} + +#if defined(_WIN32) +static void setenv(const char *name, const char *value, int overwrite) +{ + char *str; + size_t name_len, value_len; + name_len = strlen(name); + value_len = strlen(value); + str = malloc(name_len + 1 + value_len + 1); + memcpy(str, name, name_len); + str[name_len] = '='; + memcpy(str + name_len + 1, value, value_len); + str[name_len + 1 + value_len] = '\0'; + _putenv(str); + free(str); +} + +static void unsetenv(const char *name) +{ + setenv(name, "", true); +} +#endif /* _WIN32 */ + +static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *name, *value; + name = JS_ToCString(ctx, argv[0]); + if (!name) + return JS_EXCEPTION; + value = JS_ToCString(ctx, argv[1]); + if (!value) { + JS_FreeCString(ctx, name); + return JS_EXCEPTION; + } + setenv(name, value, true); + JS_FreeCString(ctx, name); + JS_FreeCString(ctx, value); + return JS_UNDEFINED; +} + +static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *name; + name = JS_ToCString(ctx, argv[0]); + if (!name) + return JS_EXCEPTION; + unsetenv(name); + JS_FreeCString(ctx, name); + return JS_UNDEFINED; +} + +/* return an object containing the list of the available environment + variables. */ +static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + char **envp; + const char *name, *p, *value; + JSValue obj; + uint32_t idx; + size_t name_len; + JSAtom atom; + int ret; + + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) + return JS_EXCEPTION; + envp = environ; + for(idx = 0; envp[idx] != NULL; idx++) { + name = envp[idx]; + p = strchr(name, '='); + name_len = p - name; + if (!p) + continue; + value = p + 1; + atom = JS_NewAtomLen(ctx, name, name_len); + if (atom == JS_ATOM_NULL) + goto fail; + ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value), + JS_PROP_C_W_E); + JS_FreeAtom(ctx, atom); + if (ret < 0) + goto fail; + } + return obj; + fail: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JS_RunGC(JS_GetRuntime(ctx)); + return JS_UNDEFINED; +} + +static int interrupt_handler(JSRuntime *rt, void *opaque) +{ + return (os_pending_signals >> SIGINT) & 1; +} + +static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + const char *str = NULL; + size_t len; + JSValue ret, obj; + JSValueConst options_obj, arg; + bool backtrace_barrier = false; + bool eval_function = false; + bool eval_module = false; + bool compile_only = false; + bool compile_module = false; + bool is_async = false; + int flags; + + if (argc >= 2) { + options_obj = argv[1]; + if (get_bool_option(ctx, &backtrace_barrier, options_obj, + "backtrace_barrier")) + return JS_EXCEPTION; + if (get_bool_option(ctx, &eval_function, options_obj, + "eval_function")) + return JS_EXCEPTION; + if (get_bool_option(ctx, &eval_module, options_obj, + "eval_module")) + return JS_EXCEPTION; + if (get_bool_option(ctx, &compile_only, options_obj, + "compile_only")) + return JS_EXCEPTION; + if (get_bool_option(ctx, &compile_module, options_obj, + "compile_module")) + return JS_EXCEPTION; + if (get_bool_option(ctx, &is_async, options_obj, + "async")) + return JS_EXCEPTION; + } + + if (eval_module) { + arg = argv[0]; + if (JS_VALUE_GET_TAG(arg) != JS_TAG_MODULE) + return JS_ThrowTypeError(ctx, "not a module"); + + if (JS_ResolveModule(ctx, arg) < 0) + return JS_EXCEPTION; + + if (js_module_set_import_meta(ctx, arg, false, false) < 0) + return JS_EXCEPTION; + + return JS_EvalFunction(ctx, JS_DupValue(ctx, arg)); + } + + if (!eval_function) { + str = JS_ToCStringLen(ctx, &len, argv[0]); + if (!str) + return JS_EXCEPTION; + } + if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) { + /* install the interrupt handler */ + JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL); + } + flags = compile_module ? JS_EVAL_TYPE_MODULE : JS_EVAL_TYPE_GLOBAL; + if (backtrace_barrier) + flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER; + if (compile_only) + flags |= JS_EVAL_FLAG_COMPILE_ONLY; + if (is_async) + flags |= JS_EVAL_FLAG_ASYNC; + if (eval_function) { + obj = JS_DupValue(ctx, argv[0]); + ret = JS_EvalFunction(ctx, obj); // takes ownership of |obj| + } else { + ret = JS_Eval(ctx, str, len, "", flags); + } + JS_FreeCString(ctx, str); + if (!ts->recv_pipe && --ts->eval_script_recurse == 0) { + /* remove the interrupt handler */ + JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL); + os_pending_signals &= ~((uint64_t)1 << SIGINT); + /* convert the uncatchable "interrupted" error into a normal error + so that it can be caught by the REPL */ + if (JS_IsException(ret)) + JS_ResetUncatchableError(ctx); + } + return ret; +} + +typedef struct { + FILE *f; + bool is_popen; +} JSSTDFile; + +static bool is_stdio(FILE *f) +{ + return f == stdin || f == stdout || f == stderr; +} + +static void js_std_file_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSThreadState *ts = js_get_thread_state(rt); + JSSTDFile *s = JS_GetOpaque(val, ts->std_file_class_id); + if (s) { + if (s->f && !is_stdio(s->f)) { +#if !defined(__wasi__) + if (s->is_popen) + pclose(s->f); + else +#endif + fclose(s->f); + } + js_free_rt(rt, s); + } +} + +static ssize_t js_get_errno(ssize_t ret) +{ + if (ret == -1) + ret = -errno; + return ret; +} + +static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int err; + if (JS_ToInt32(ctx, &err, argv[0])) + return JS_EXCEPTION; + return JS_NewString(ctx, strerror(err)); +} + +static JSValue js_new_std_file(JSContext *ctx, FILE *f, bool is_popen) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSSTDFile *s; + JSValue obj; + obj = JS_NewObjectClass(ctx, ts->std_file_class_id); + if (JS_IsException(obj)) + return obj; + s = js_mallocz(ctx, sizeof(*s)); + if (!s) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + s->is_popen = is_popen; + s->f = f; + JS_SetOpaque(obj, s); + return obj; +} + +static void js_set_error_object(JSContext *ctx, JSValueConst obj, int err) +{ + if (!JS_IsUndefined(obj)) { + JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err)); + } +} + +static JSValue js_std_open(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *filename, *mode = NULL; + FILE *f; + int err; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + goto fail; + mode = JS_ToCString(ctx, argv[1]); + if (!mode) + goto fail; + if (mode[strspn(mode, "rwa+bx")] != '\0') { + JS_ThrowTypeError(ctx, "invalid file mode"); + goto fail; + } + + f = fopen(filename, mode); + if (!f) + err = errno; + else + err = 0; + if (argc >= 3) + js_set_error_object(ctx, argv[2], err); + JS_FreeCString(ctx, filename); + JS_FreeCString(ctx, mode); + if (!f) + return JS_NULL; + return js_new_std_file(ctx, f, false); + fail: + JS_FreeCString(ctx, filename); + JS_FreeCString(ctx, mode); + return JS_EXCEPTION; +} + +#if !defined(__wasi__) +static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *filename, *mode = NULL; + FILE *f; + int err; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + goto fail; + mode = JS_ToCString(ctx, argv[1]); + if (!mode) + goto fail; + if (strcmp(mode, "r") && strcmp(mode, "w")) { + JS_ThrowTypeError(ctx, "invalid file mode"); + goto fail; + } + + f = popen(filename, mode); + if (!f) + err = errno; + else + err = 0; + if (argc >= 3) + js_set_error_object(ctx, argv[2], err); + JS_FreeCString(ctx, filename); + JS_FreeCString(ctx, mode); + if (!f) + return JS_NULL; + return js_new_std_file(ctx, f, true); + fail: + JS_FreeCString(ctx, filename); + JS_FreeCString(ctx, mode); + return JS_EXCEPTION; +} +#endif // !defined(__wasi__) + +static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *mode; + FILE *f; + int fd, err; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + mode = JS_ToCString(ctx, argv[1]); + if (!mode) + goto fail; + if (mode[strspn(mode, "rwa+")] != '\0') { + JS_ThrowTypeError(ctx, "invalid file mode"); + goto fail; + } + + f = fdopen(fd, mode); + if (!f) + err = errno; + else + err = 0; + if (argc >= 3) + js_set_error_object(ctx, argv[2], err); + JS_FreeCString(ctx, mode); + if (!f) + return JS_NULL; + return js_new_std_file(ctx, f, false); + fail: + JS_FreeCString(ctx, mode); + return JS_EXCEPTION; +} + +#if !defined(__wasi__) +static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f; + f = tmpfile(); + if (argc >= 1) + js_set_error_object(ctx, argv[0], f ? 0 : errno); + if (!f) + return JS_NULL; + return js_new_std_file(ctx, f, false); +} +#endif + +static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + return js_printf_internal(ctx, argc, argv, NULL); +} + +static JSValue js_std_printf(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + return js_printf_internal(ctx, argc, argv, stdout); +} + +static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSSTDFile *s = JS_GetOpaque2(ctx, obj, ts->std_file_class_id); + if (!s) + return NULL; + if (!s->f) { + JS_ThrowTypeError(ctx, "invalid file handle"); + return NULL; + } + return s->f; +} + +static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + FILE *f; + int i; + const char *str; + size_t len; + + if (magic == 0) { + f = stdout; + } else { + f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + } + + for(i = 0; i < argc; i++) { + str = JS_ToCStringLen(ctx, &len, argv[i]); + if (!str) + return JS_EXCEPTION; + fwrite(str, 1, len, f); + JS_FreeCString(ctx, str); + } + return JS_UNDEFINED; +} + +static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSSTDFile *s = JS_GetOpaque2(ctx, this_val, ts->std_file_class_id); + int err; + if (!s) + return JS_EXCEPTION; + if (!s->f) + return JS_ThrowTypeError(ctx, "invalid file handle"); + if (is_stdio(s->f)) + return JS_ThrowTypeError(ctx, "cannot close stdio"); +#if !defined(__wasi__) + if (s->is_popen) + err = js_get_errno(pclose(s->f)); + else +#endif + err = js_get_errno(fclose(s->f)); + s->f = NULL; + return JS_NewInt32(ctx, err); +} + +static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return js_printf_internal(ctx, argc, argv, f); +} + +static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + fflush(f); + return JS_UNDEFINED; +} + +static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int is_bigint) +{ + FILE *f = js_std_file_get(ctx, this_val); + int64_t pos; + if (!f) + return JS_EXCEPTION; +#if defined(__linux__) || defined(__GLIBC__) + pos = ftello(f); +#else + pos = ftell(f); +#endif + if (is_bigint) + return JS_NewBigInt64(ctx, pos); + else + return JS_NewInt64(ctx, pos); +} + +static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + int64_t pos; + int whence, ret; + if (!f) + return JS_EXCEPTION; + if (JS_ToInt64Ext(ctx, &pos, argv[0])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &whence, argv[1])) + return JS_EXCEPTION; +#if defined(__linux__) || defined(__GLIBC__) + ret = fseeko(f, pos, whence); +#else + ret = fseek(f, pos, whence); +#endif + if (ret < 0) + ret = -errno; + return JS_NewInt32(ctx, ret); +} + +static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return JS_NewBool(ctx, feof(f)); +} + +static JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return JS_NewBool(ctx, ferror(f)); +} + +static JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + clearerr(f); + return JS_UNDEFINED; +} + +static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return JS_NewInt32(ctx, fileno(f)); +} + +static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + FILE *f = js_std_file_get(ctx, this_val); + uint64_t pos, len; + size_t size, ret; + uint8_t *buf; + + if (!f) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &pos, argv[1])) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &len, argv[2])) + return JS_EXCEPTION; + buf = JS_GetArrayBuffer(ctx, &size, argv[0]); + if (!buf) + return JS_EXCEPTION; + if (pos + len > size) + return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); + if (magic) + ret = fwrite(buf + pos, 1, len, f); + else + ret = fread(buf + pos, 1, len, f); + return JS_NewInt64(ctx, ret); +} + +/* XXX: could use less memory and go faster */ +static JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + int c; + DynBuf dbuf; + JSValue obj; + + if (!f) + return JS_EXCEPTION; + + js_std_dbuf_init(ctx, &dbuf); + for(;;) { + c = fgetc(f); + if (c == EOF) { + if (dbuf.size == 0) { + /* EOF */ + dbuf_free(&dbuf); + return JS_NULL; + } else { + break; + } + } + if (c == '\n') + break; + if (dbuf_putc(&dbuf, c)) { + dbuf_free(&dbuf); + return JS_ThrowOutOfMemory(ctx); + } + } + obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size); + dbuf_free(&dbuf); + return obj; +} + +/* XXX: could use less memory and go faster */ +static JSValue js_std_file_readAs(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + FILE *f = js_std_file_get(ctx, this_val); + int c; + DynBuf dbuf; + JSValue obj; + uint64_t max_size64; + size_t max_size; + JSValueConst max_size_val; + + if (!f) + return JS_EXCEPTION; + + if (argc >= 1) + max_size_val = argv[0]; + else + max_size_val = JS_UNDEFINED; + max_size = (size_t)-1; + if (!JS_IsUndefined(max_size_val)) { + if (JS_ToIndex(ctx, &max_size64, max_size_val)) + return JS_EXCEPTION; + if (max_size64 < max_size) + max_size = max_size64; + } + + js_std_dbuf_init(ctx, &dbuf); + while (max_size != 0) { + c = fgetc(f); + if (c == EOF) + break; + if (dbuf_putc(&dbuf, c)) { + dbuf_free(&dbuf); + return JS_EXCEPTION; + } + max_size--; + } + if (magic) { + obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size); + } else { + obj = JS_NewArrayBufferCopy(ctx, dbuf.buf, dbuf.size); + } + dbuf_free(&dbuf); + return obj; +} + +static JSValue js_std_file_getByte(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return JS_NewInt32(ctx, fgetc(f)); +} + +static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + int c; + if (!f) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &c, argv[0])) + return JS_EXCEPTION; + c = fputc(c, f); + return JS_NewInt32(ctx, c); +} + +/* urlGet */ +#if !defined(__wasi__) + +#define URL_GET_PROGRAM "curl -s -i --" +#define URL_GET_BUF_SIZE 4096 + +static int http_get_header_line(FILE *f, char *buf, size_t buf_size, + DynBuf *dbuf) +{ + int c; + char *p; + + p = buf; + for(;;) { + c = fgetc(f); + if (c < 0) + return -1; + if ((p - buf) < buf_size - 1) + *p++ = c; + if (dbuf) + dbuf_putc(dbuf, c); + if (c == '\n') + break; + } + *p = '\0'; + return 0; +} + +static int http_get_status(const char *buf) +{ + const char *p = buf; + while (*p != ' ' && *p != '\0') + p++; + if (*p != ' ') + return 0; + while (*p == ' ') + p++; + return atoi(p); +} + +static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *url; + DynBuf cmd_buf; + DynBuf data_buf_s, *data_buf = &data_buf_s; + DynBuf header_buf_s, *header_buf = &header_buf_s; + char *buf; + size_t i, len; + int status; + JSValue response = JS_UNDEFINED, ret_obj; + JSValueConst options_obj; + FILE *f; + bool binary_flag, full_flag; + + url = JS_ToCString(ctx, argv[0]); + if (!url) + return JS_EXCEPTION; + + binary_flag = false; + full_flag = false; + + if (argc >= 2) { + options_obj = argv[1]; + + if (get_bool_option(ctx, &binary_flag, options_obj, "binary")) + goto fail_obj; + + if (get_bool_option(ctx, &full_flag, options_obj, "full")) { + fail_obj: + JS_FreeCString(ctx, url); + return JS_EXCEPTION; + } + } + + js_std_dbuf_init(ctx, &cmd_buf); + dbuf_printf(&cmd_buf, "%s '", URL_GET_PROGRAM); + for(i = 0; url[i] != '\0'; i++) { + unsigned char c = url[i]; + switch (c) { + case '\'': + /* shell single quoted string does not support \' */ + dbuf_putstr(&cmd_buf, "'\\''"); + break; + case '[': case ']': case '{': case '}': case '\\': + /* prevent interpretation by curl as range or set specification */ + dbuf_putc(&cmd_buf, '\\'); + /* FALLTHROUGH */ + default: + dbuf_putc(&cmd_buf, c); + break; + } + } + JS_FreeCString(ctx, url); + dbuf_putstr(&cmd_buf, "'"); + dbuf_putc(&cmd_buf, '\0'); + if (dbuf_error(&cmd_buf)) { + dbuf_free(&cmd_buf); + return JS_EXCEPTION; + } + // printf("%s\n", (char *)cmd_buf.buf); + f = popen((char *)cmd_buf.buf, "r"); + dbuf_free(&cmd_buf); + if (!f) { + return JS_ThrowTypeError(ctx, "could not start curl"); + } + + js_std_dbuf_init(ctx, data_buf); + js_std_dbuf_init(ctx, header_buf); + + buf = js_malloc(ctx, URL_GET_BUF_SIZE); + if (!buf) + goto fail; + + /* get the HTTP status */ + if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) { + status = 0; + goto bad_header; + } + status = http_get_status(buf); + if (!full_flag && !(status >= 200 && status <= 299)) { + goto bad_header; + } + + /* wait until there is an empty line */ + for(;;) { + if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) { + bad_header: + response = JS_NULL; + goto done; + } + if (!strcmp(buf, "\r\n")) + break; + } + if (dbuf_error(header_buf)) + goto fail; + header_buf->size -= 2; /* remove the trailing CRLF */ + + /* download the data */ + for(;;) { + len = fread(buf, 1, URL_GET_BUF_SIZE, f); + if (len == 0) + break; + dbuf_put(data_buf, (uint8_t *)buf, len); + } + if (dbuf_error(data_buf)) + goto fail; + if (binary_flag) { + response = JS_NewArrayBufferCopy(ctx, + data_buf->buf, data_buf->size); + } else { + response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size); + } + if (JS_IsException(response)) + goto fail; + done: + js_free(ctx, buf); + buf = NULL; + pclose(f); + f = NULL; + dbuf_free(data_buf); + data_buf = NULL; + + if (full_flag) { + ret_obj = JS_NewObject(ctx); + if (JS_IsException(ret_obj)) + goto fail; + JS_DefinePropertyValueStr(ctx, ret_obj, "response", + response, + JS_PROP_C_W_E); + if (!JS_IsNull(response)) { + JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders", + JS_NewStringLen(ctx, (char *)header_buf->buf, + header_buf->size), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, ret_obj, "status", + JS_NewInt32(ctx, status), + JS_PROP_C_W_E); + } + } else { + ret_obj = response; + } + dbuf_free(header_buf); + return ret_obj; + fail: + if (f) + pclose(f); + js_free(ctx, buf); + if (data_buf) + dbuf_free(data_buf); + if (header_buf) + dbuf_free(header_buf); + JS_FreeValue(ctx, response); + return JS_EXCEPTION; +} +#endif // !defined(__wasi__) + +static JSClassDef js_std_file_class = { + "FILE", + .finalizer = js_std_file_finalizer, +}; + +static const JSCFunctionListEntry js_std_error_props[] = { + /* various errno values */ +#define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE ) + DEF(EINVAL), + DEF(EIO), + DEF(EACCES), + DEF(EEXIST), + DEF(ENOSPC), + DEF(ENOSYS), + DEF(EBUSY), + DEF(ENOENT), + DEF(EPERM), + DEF(EPIPE), + DEF(EBADF), +#undef DEF +}; + +static const JSCFunctionListEntry js_std_funcs[] = { + JS_CFUNC_DEF("exit", 1, js_std_exit ), + JS_CFUNC_DEF("gc", 0, js_std_gc ), + JS_CFUNC_DEF("evalScript", 1, js_evalScript ), + JS_CFUNC_DEF("loadScript", 1, js_loadScript ), + JS_CFUNC_DEF("getenv", 1, js_std_getenv ), + JS_CFUNC_DEF("setenv", 1, js_std_setenv ), + JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ), + JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ), +#if !defined(__wasi__) + JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ), +#endif + JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ), + JS_CFUNC_DEF("writeFile", 2, js_std_writeFile ), + JS_CFUNC_DEF("strerror", 1, js_std_strerror ), + + /* FILE I/O */ + JS_CFUNC_DEF("open", 2, js_std_open ), +#if !defined(__wasi__) + JS_CFUNC_DEF("popen", 2, js_std_popen ), + JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ), +#endif + JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ), + JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ), + JS_CFUNC_DEF("printf", 1, js_std_printf ), + JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ), + JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ), + JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ), + JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ), + JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE), +}; + +static const JSCFunctionListEntry js_std_file_proto_funcs[] = { + JS_CFUNC_DEF("close", 0, js_std_file_close ), + JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ), + JS_CFUNC_DEF("printf", 1, js_std_file_printf ), + JS_CFUNC_DEF("flush", 0, js_std_file_flush ), + JS_CFUNC_MAGIC_DEF("tell", 0, js_std_file_tell, 0 ), + JS_CFUNC_MAGIC_DEF("tello", 0, js_std_file_tell, 1 ), + JS_CFUNC_DEF("seek", 2, js_std_file_seek ), + JS_CFUNC_DEF("eof", 0, js_std_file_eof ), + JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ), + JS_CFUNC_DEF("error", 0, js_std_file_error ), + JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ), + JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ), + JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ), + JS_CFUNC_DEF("getline", 0, js_std_file_getline ), + JS_CFUNC_MAGIC_DEF("readAsArrayBuffer", 0, js_std_file_readAs, 0 ), + JS_CFUNC_MAGIC_DEF("readAsString", 0, js_std_file_readAs, 1 ), + JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ), + JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ), + /* setvbuf, ... */ +}; + +static int js_std_init(JSContext *ctx, JSModuleDef *m) +{ + JSValue proto; + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + + /* FILE class */ + /* the class ID is created once */ + JS_NewClassID(rt, &ts->std_file_class_id); + /* the class is created once per runtime */ + JS_NewClass(rt, ts->std_file_class_id, &js_std_file_class); + proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs, + countof(js_std_file_proto_funcs)); + JS_SetClassProto(ctx, ts->std_file_class_id, proto); + + JS_SetModuleExportList(ctx, m, js_std_funcs, + countof(js_std_funcs)); + JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, false)); + JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, false)); + JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, false)); + return 0; +} + +JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_std_init); + if (!m) + return NULL; + JS_AddModuleExportList(ctx, m, js_std_funcs, countof(js_std_funcs)); + JS_AddModuleExport(ctx, m, "in"); + JS_AddModuleExport(ctx, m, "out"); + JS_AddModuleExport(ctx, m, "err"); + return m; +} + +/**********************************************************/ +/* 'os' object */ + +static JSValue js_os_open(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *filename; + int flags, mode, ret; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &flags, argv[1])) + goto fail; + if (argc >= 3 && !JS_IsUndefined(argv[2])) { + if (JS_ToInt32(ctx, &mode, argv[2])) { + fail: + JS_FreeCString(ctx, filename); + return JS_EXCEPTION; + } + } else { + mode = 0666; + } +#if defined(_WIN32) + /* force binary mode by default */ + if (!(flags & O_TEXT)) + flags |= O_BINARY; +#endif + ret = js_get_errno(open(filename, flags, mode)); + JS_FreeCString(ctx, filename); + return JS_NewInt32(ctx, ret); +} + +static JSValue js_os_close(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd, ret; + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + ret = js_get_errno(close(fd)); + return JS_NewInt32(ctx, ret); +} + +static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd, whence; + int64_t pos, ret; + bool is_bigint; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + is_bigint = JS_IsBigInt(argv[1]); + if (JS_ToInt64Ext(ctx, &pos, argv[1])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &whence, argv[2])) + return JS_EXCEPTION; + ret = lseek(fd, pos, whence); + if (ret == -1) + ret = -errno; + if (is_bigint) + return JS_NewBigInt64(ctx, ret); + else + return JS_NewInt64(ctx, ret); +} + +static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + int fd; + uint64_t pos, len; + size_t size; + ssize_t ret; + uint8_t *buf; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &pos, argv[2])) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &len, argv[3])) + return JS_EXCEPTION; + buf = JS_GetArrayBuffer(ctx, &size, argv[1]); + if (!buf) + return JS_EXCEPTION; + if (pos + len > size) + return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); + if (magic) + ret = js_get_errno(write(fd, buf + pos, len)); + else + ret = js_get_errno(read(fd, buf + pos, len)); + return JS_NewInt64(ctx, ret); +} + +static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd; + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + return JS_NewBool(ctx, (isatty(fd) != 0)); +} + +#if defined(_WIN32) +static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd; + HANDLE handle; + CONSOLE_SCREEN_BUFFER_INFO info; + JSValue obj; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + handle = (HANDLE)_get_osfhandle(fd); + + if (!GetConsoleScreenBufferInfo(handle, &info)) + return JS_NULL; + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) + return obj; + JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, info.dwSize.X), JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, info.dwSize.Y), JS_PROP_C_W_E); + return obj; +} + +/* Windows 10 built-in VT100 emulation */ +#define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 + +static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd; + HANDLE handle; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + handle = (HANDLE)_get_osfhandle(fd); + SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT); + _setmode(fd, _O_BINARY); + if (fd == 0) { + handle = (HANDLE)_get_osfhandle(1); /* corresponding output */ + SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING); + } + return JS_UNDEFINED; +} +#elif !defined(__wasi__) +static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd; + struct winsize ws; + JSValue obj; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + if (ioctl(fd, TIOCGWINSZ, &ws) == 0 && + ws.ws_col >= 4 && ws.ws_row >= 4) { + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) + return obj; + JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ws.ws_col), JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, ws.ws_row), JS_PROP_C_W_E); + return obj; + } else { + return JS_NULL; + } +} + +static struct termios oldtty; + +static void term_exit(void) +{ + tcsetattr(0, TCSANOW, &oldtty); +} + +/* XXX: should add a way to go back to normal mode */ +static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + struct termios tty; + int fd; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + + memset(&tty, 0, sizeof(tty)); + tcgetattr(fd, &tty); + oldtty = tty; + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + tcsetattr(fd, TCSANOW, &tty); + + atexit(term_exit); + return JS_UNDEFINED; +} + +#endif /* !_WIN32 && !__wasi__ */ + +static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *filename; + int ret; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + return JS_EXCEPTION; +#if defined(_WIN32) + { + struct stat st; + if (stat(filename, &st) == 0 && (st.st_mode & _S_IFDIR)) { + ret = rmdir(filename); + } else { + ret = unlink(filename); + } + } +#else + ret = remove(filename); +#endif + ret = js_get_errno(ret); + JS_FreeCString(ctx, filename); + return JS_NewInt32(ctx, ret); +} + +static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *oldpath, *newpath; + int ret; + + oldpath = JS_ToCString(ctx, argv[0]); + if (!oldpath) + return JS_EXCEPTION; + newpath = JS_ToCString(ctx, argv[1]); + if (!newpath) { + JS_FreeCString(ctx, oldpath); + return JS_EXCEPTION; + } + ret = js_get_errno(rename(oldpath, newpath)); + JS_FreeCString(ctx, oldpath); + JS_FreeCString(ctx, newpath); + return JS_NewInt32(ctx, ret); +} + +static bool is_main_thread(JSRuntime *rt) +{ + JSThreadState *ts = js_get_thread_state(rt); + return !ts->recv_pipe; +} + +static JSOSRWHandler *find_rh(JSThreadState *ts, int fd) +{ + JSOSRWHandler *rh; + struct list_head *el; + + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + if (rh->fd == fd) + return rh; + } + return NULL; +} + +static void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh) +{ + int i; + list_del(&rh->link); + for(i = 0; i < 2; i++) { + JS_FreeValueRT(rt, rh->rw_func[i]); + } + js_free_rt(rt, rh); +} + +static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSOSRWHandler *rh; + int fd; + JSValueConst func; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + func = argv[1]; + if (JS_IsNull(func)) { + rh = find_rh(ts, fd); + if (rh) { + JS_FreeValue(ctx, rh->rw_func[magic]); + rh->rw_func[magic] = JS_NULL; + if (JS_IsNull(rh->rw_func[0]) && + JS_IsNull(rh->rw_func[1])) { + /* remove the entry */ + free_rw_handler(JS_GetRuntime(ctx), rh); + } + } + } else { + if (!JS_IsFunction(ctx, func)) + return JS_ThrowTypeError(ctx, "not a function"); + rh = find_rh(ts, fd); + if (!rh) { + rh = js_mallocz(ctx, sizeof(*rh)); + if (!rh) + return JS_EXCEPTION; + rh->fd = fd; + rh->rw_func[0] = JS_NULL; + rh->rw_func[1] = JS_NULL; + list_add_tail(&rh->link, &ts->os_rw_handlers); + } + JS_FreeValue(ctx, rh->rw_func[magic]); + rh->rw_func[magic] = JS_DupValue(ctx, func); + } + return JS_UNDEFINED; +} + +static JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num) +{ + JSOSSignalHandler *sh; + struct list_head *el; + list_for_each(el, &ts->os_signal_handlers) { + sh = list_entry(el, JSOSSignalHandler, link); + if (sh->sig_num == sig_num) + return sh; + } + return NULL; +} + +static void free_sh(JSRuntime *rt, JSOSSignalHandler *sh) +{ + list_del(&sh->link); + JS_FreeValueRT(rt, sh->func); + js_free_rt(rt, sh); +} + +static void os_signal_handler(int sig_num) +{ + os_pending_signals |= ((uint64_t)1 << sig_num); +} + +#if defined(_WIN32) +typedef void (*sighandler_t)(int sig_num); +#endif + +static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSOSSignalHandler *sh; + uint32_t sig_num; + JSValueConst func; + sighandler_t handler; + + if (!is_main_thread(rt)) + return JS_ThrowTypeError(ctx, "signal handler can only be set in the main thread"); + + if (JS_ToUint32(ctx, &sig_num, argv[0])) + return JS_EXCEPTION; + if (sig_num >= 64) + return JS_ThrowRangeError(ctx, "invalid signal number"); + func = argv[1]; + /* func = null: SIG_DFL, func = undefined, SIG_IGN */ + if (JS_IsNull(func) || JS_IsUndefined(func)) { + sh = find_sh(ts, sig_num); + if (sh) { + free_sh(JS_GetRuntime(ctx), sh); + } + if (JS_IsNull(func)) + handler = SIG_DFL; + else + handler = SIG_IGN; + signal(sig_num, handler); + } else { + if (!JS_IsFunction(ctx, func)) + return JS_ThrowTypeError(ctx, "not a function"); + sh = find_sh(ts, sig_num); + if (!sh) { + sh = js_mallocz(ctx, sizeof(*sh)); + if (!sh) + return JS_EXCEPTION; + sh->sig_num = sig_num; + list_add_tail(&sh->link, &ts->os_signal_handlers); + } + JS_FreeValue(ctx, sh->func); + sh->func = JS_DupValue(ctx, func); + signal(sig_num, os_signal_handler); + } + return JS_UNDEFINED; +} + +#if !defined(_WIN32) && !defined(__wasi__) +static JSValue js_os_cputime(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + struct rusage ru; + int64_t cputime; + + cputime = 0; + if (!getrusage(RUSAGE_SELF, &ru)) + cputime = (int64_t)ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec; + + return JS_NewInt64(ctx, cputime); +} +#endif + +static JSValue js_os_exepath(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + char buf[JS__PATH_MAX]; + size_t len = sizeof(buf); + if (js_exepath(buf, &len)) + return JS_UNDEFINED; + return JS_NewStringLen(ctx, buf, len); +} + +static JSValue js_os_now(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + return JS_NewInt64(ctx, js__hrtime_ns() / 1000); +} + +static uint64_t js__hrtime_ms(void) +{ + return js__hrtime_ns() / (1000 * 1000); +} + +static void free_timer(JSRuntime *rt, JSOSTimer *th) +{ + list_del(&th->link); + JS_FreeValueRT(rt, th->func); + js_free_rt(rt, th); +} + +// TODO(bnoordhuis) accept string as first arg and eval at timer expiry +// TODO(bnoordhuis) retain argv[2..] as args for callback if argc > 2 +static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + int64_t delay; + JSValueConst func; + JSOSTimer *th; + + func = argv[0]; + if (!JS_IsFunction(ctx, func)) + return JS_ThrowTypeError(ctx, "not a function"); + if (JS_ToInt64(ctx, &delay, argv[1])) + return JS_EXCEPTION; + if (delay < 1) + delay = 1; + th = js_mallocz(ctx, sizeof(*th)); + if (!th) + return JS_EXCEPTION; + th->timer_id = ts->next_timer_id++; + if (ts->next_timer_id > MAX_SAFE_INTEGER) + ts->next_timer_id = 1; + th->repeats = (magic > 0); + th->timeout = js__hrtime_ms() + delay; + th->delay = delay; + th->func = JS_DupValue(ctx, func); + list_add_tail(&th->link, &ts->os_timers); + return JS_NewInt64(ctx, th->timer_id); +} + +static JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id) +{ + struct list_head *el; + if (timer_id <= 0) + return NULL; + list_for_each(el, &ts->os_timers) { + JSOSTimer *th = list_entry(el, JSOSTimer, link); + if (th->timer_id == timer_id) + return th; + } + return NULL; +} + +static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSOSTimer *th; + int64_t timer_id; + + if (JS_ToInt64(ctx, &timer_id, argv[0])) + return JS_EXCEPTION; + th = find_timer_by_id(ts, timer_id); + if (!th) + return JS_UNDEFINED; + free_timer(rt, th); + return JS_UNDEFINED; +} + +/* return a promise */ +static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + int64_t delay; + JSOSTimer *th; + JSValue promise, resolving_funcs[2]; + + if (JS_ToInt64(ctx, &delay, argv[0])) + return JS_EXCEPTION; + promise = JS_NewPromiseCapability(ctx, resolving_funcs); + if (JS_IsException(promise)) + return JS_EXCEPTION; + + th = js_mallocz(ctx, sizeof(*th)); + if (!th) { + JS_FreeValue(ctx, promise); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return JS_EXCEPTION; + } + th->timer_id = -1; + th->timeout = js__hrtime_ms() + delay; + th->func = JS_DupValue(ctx, resolving_funcs[0]); + list_add_tail(&th->link, &ts->os_timers); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return promise; +} + +static int call_handler(JSContext *ctx, JSValue func) +{ + int r; + JSValue ret, func1; + /* 'func' might be destroyed when calling itself (if it frees the + handler), so must take extra care */ + func1 = JS_DupValue(ctx, func); + ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL); + JS_FreeValue(ctx, func1); + r = 0; + if (JS_IsException(ret)) + r = -1; + JS_FreeValue(ctx, ret); + return r; +} + +static int js_os_run_timers(JSRuntime *rt, JSContext *ctx, JSThreadState *ts, int *min_delay) +{ + JSValue func; + JSOSTimer *th; + int64_t cur_time, delay; + struct list_head *el; + int r; + + if (list_empty(&ts->os_timers)) { + *min_delay = -1; + return 0; + } + + cur_time = js__hrtime_ms(); + *min_delay = INT32_MAX; + + list_for_each(el, &ts->os_timers) { + th = list_entry(el, JSOSTimer, link); + delay = th->timeout - cur_time; + if (delay > 0) { + *min_delay = min_int(*min_delay, delay); + } else { + *min_delay = 0; + func = JS_DupValueRT(rt, th->func); + if (th->repeats) + th->timeout = cur_time + th->delay; + else + free_timer(rt, th); + r = call_handler(ctx, func); + JS_FreeValueRT(rt, func); + return r; + } + } + + return 0; +} + +#ifdef USE_WORKER + +#ifdef _WIN32 + +static int js_waker_init(JSWaker *w) +{ + w->handle = CreateEvent(NULL, TRUE, FALSE, NULL); + return w->handle ? 0 : -1; +} + +static void js_waker_signal(JSWaker *w) +{ + SetEvent(w->handle); +} + +static void js_waker_clear(JSWaker *w) +{ + ResetEvent(w->handle); +} + +static void js_waker_close(JSWaker *w) +{ + CloseHandle(w->handle); + w->handle = INVALID_HANDLE_VALUE; +} + +#else // !_WIN32 + +static int js_waker_init(JSWaker *w) +{ + int fds[2]; + + if (pipe(fds) < 0) + return -1; + w->read_fd = fds[0]; + w->write_fd = fds[1]; + return 0; +} + +static void js_waker_signal(JSWaker *w) +{ + int ret; + + for(;;) { + ret = write(w->write_fd, "", 1); + if (ret == 1) + break; + if (ret < 0 && (errno != EAGAIN || errno != EINTR)) + break; + } +} + +static void js_waker_clear(JSWaker *w) +{ + uint8_t buf[16]; + int ret; + + for(;;) { + ret = read(w->read_fd, buf, sizeof(buf)); + if (ret >= 0) + break; + if (errno != EAGAIN && errno != EINTR) + break; + } +} + +static void js_waker_close(JSWaker *w) +{ + close(w->read_fd); + close(w->write_fd); + w->read_fd = -1; + w->write_fd = -1; +} + +#endif // _WIN32 + +static void js_free_message(JSWorkerMessage *msg); + +/* return 1 if a message was handled, 0 if no message */ +static int handle_posted_message(JSRuntime *rt, JSContext *ctx, + JSWorkerMessageHandler *port) +{ + JSWorkerMessagePipe *ps = port->recv_pipe; + int ret; + struct list_head *el; + JSWorkerMessage *msg; + JSValue obj, data_obj, func, retval; + + js_mutex_lock(&ps->mutex); + if (!list_empty(&ps->msg_queue)) { + el = ps->msg_queue.next; + msg = list_entry(el, JSWorkerMessage, link); + + /* remove the message from the queue */ + list_del(&msg->link); + + // drain read end of pipe + if (list_empty(&ps->msg_queue)) + js_waker_clear(&ps->waker); + + js_mutex_unlock(&ps->mutex); + + data_obj = JS_ReadObject(ctx, msg->data, msg->data_len, + JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE); + + js_free_message(msg); + + if (JS_IsException(data_obj)) + goto fail; + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) { + JS_FreeValue(ctx, data_obj); + goto fail; + } + JS_DefinePropertyValueStr(ctx, obj, "data", data_obj, JS_PROP_C_W_E); + + /* 'func' might be destroyed when calling itself (if it frees the + handler), so must take extra care */ + func = JS_DupValue(ctx, port->on_message_func); + retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj); + JS_FreeValue(ctx, obj); + JS_FreeValue(ctx, func); + if (JS_IsException(retval)) { + fail: + js_std_dump_error(ctx); + } else { + JS_FreeValue(ctx, retval); + } + ret = 1; + } else { + js_mutex_unlock(&ps->mutex); + ret = 0; + } + return ret; +} + +#endif // USE_WORKER + +#if defined(_WIN32) +static int js_os_poll(JSContext *ctx) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + int min_delay, count; + JSOSRWHandler *rh; + struct list_head *el; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64 + + /* XXX: handle signals if useful */ + + if (js_os_run_timers(rt, ctx, ts, &min_delay)) + return -1; + if (min_delay == 0) + return 0; // expired timer + if (min_delay < 0) + if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->port_list)) + return -1; /* no more events */ + + count = 0; + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) + handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin + if (count == (int)countof(handles)) + break; + } + + list_for_each(el, &ts->port_list) { + JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); + if (JS_IsNull(port->on_message_func)) + continue; + handles[count++] = port->recv_pipe->waker.handle; + if (count == (int)countof(handles)) + break; + } + + if (count > 0) { + DWORD ret, timeout = INFINITE; + if (min_delay != -1) + timeout = min_delay; + ret = WaitForMultipleObjects(count, handles, FALSE, timeout); + if (ret < count) { + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) { + return call_handler(ctx, rh->rw_func[0]); + /* must stop because the list may have been modified */ + } + } + + list_for_each(el, &ts->port_list) { + JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); + if (!JS_IsNull(port->on_message_func)) { + JSWorkerMessagePipe *ps = port->recv_pipe; + if (ps->waker.handle == handles[ret]) { + if (handle_posted_message(rt, ctx, port)) + goto done; + } + } + } + } + } else { + Sleep(min_delay); + } +done: + return 0; +} +#else // !defined(_WIN32) +static int js_os_poll(JSContext *ctx) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + int r, w, ret, nfds, min_delay; + JSOSRWHandler *rh; + struct list_head *el; + struct pollfd *pfd, *pfds, pfds_local[64]; + + /* only check signals in the main thread */ + if (!ts->recv_pipe && + unlikely(os_pending_signals != 0)) { + JSOSSignalHandler *sh; + uint64_t mask; + + list_for_each(el, &ts->os_signal_handlers) { + sh = list_entry(el, JSOSSignalHandler, link); + mask = (uint64_t)1 << sh->sig_num; + if (os_pending_signals & mask) { + os_pending_signals &= ~mask; + return call_handler(ctx, sh->func); + } + } + } + + if (js_os_run_timers(rt, ctx, ts, &min_delay)) + return -1; + if (min_delay == 0) + return 0; // expired timer + if (min_delay < 0) + if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->port_list)) + return -1; /* no more events */ + + nfds = 0; + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + nfds += (!JS_IsNull(rh->rw_func[0]) || !JS_IsNull(rh->rw_func[1])); + } + +#ifdef USE_WORKER + list_for_each(el, &ts->port_list) { + JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); + nfds += !JS_IsNull(port->on_message_func); + } +#endif // USE_WORKER + + pfd = pfds = pfds_local; + if (nfds > (int)countof(pfds_local)) { + pfd = pfds = js_malloc(ctx, nfds * sizeof(*pfd)); + if (!pfd) + return -1; + } + + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + r = POLLIN * !JS_IsNull(rh->rw_func[0]); + w = POLLOUT * !JS_IsNull(rh->rw_func[1]); + if (r || w) + *pfd++ = (struct pollfd){rh->fd, r|w, 0}; + } + +#ifdef USE_WORKER + list_for_each(el, &ts->port_list) { + JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); + if (!JS_IsNull(port->on_message_func)) { + JSWorkerMessagePipe *ps = port->recv_pipe; + *pfd++ = (struct pollfd){ps->waker.read_fd, POLLIN, 0}; + } + } +#endif // USE_WORKER + + // FIXME(bnoordhuis) the loop below is quadratic in theory but + // linear-ish in practice because we bail out on the first hit, + // i.e., it's probably good enough for now + ret = 0; + nfds = poll(pfds, nfds, min_delay); + for (pfd = pfds; nfds-- > 0; pfd++) { + rh = find_rh(ts, pfd->fd); + if (rh) { + r = (POLLERR|POLLHUP|POLLNVAL|POLLIN) * !JS_IsNull(rh->rw_func[0]); + w = (POLLERR|POLLHUP|POLLNVAL|POLLOUT) * !JS_IsNull(rh->rw_func[1]); + if (r & pfd->revents) { + ret = call_handler(ctx, rh->rw_func[0]); + goto done; + /* must stop because the list may have been modified */ + } + if (w & pfd->revents) { + ret = call_handler(ctx, rh->rw_func[1]); + goto done; + /* must stop because the list may have been modified */ + } + } else { +#ifdef USE_WORKER + list_for_each(el, &ts->port_list) { + JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); + if (!JS_IsNull(port->on_message_func)) { + JSWorkerMessagePipe *ps = port->recv_pipe; + if (pfd->fd == ps->waker.read_fd) { + if (handle_posted_message(rt, ctx, port)) + goto done; + } + } + } +#endif // USE_WORKER + } + } +done: + if (pfds != pfds_local) + js_free(ctx, pfds); + return ret; +} +#endif // defined(_WIN32) + + +static JSValue make_obj_error(JSContext *ctx, + JSValue obj, + int err) +{ + JSValue arr; + if (JS_IsException(obj)) + return obj; + arr = JS_NewArray(ctx); + if (JS_IsException(arr)) + return JS_EXCEPTION; + JS_DefinePropertyValueUint32(ctx, arr, 0, obj, + JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, arr, 1, JS_NewInt32(ctx, err), + JS_PROP_C_W_E); + return arr; +} + +static JSValue make_string_error(JSContext *ctx, + const char *buf, + int err) +{ + return make_obj_error(ctx, JS_NewString(ctx, buf), err); +} + +/* return [cwd, errorcode] */ +static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + char buf[JS__PATH_MAX]; + int err; + + if (!getcwd(buf, sizeof(buf))) { + buf[0] = '\0'; + err = errno; + } else { + err = 0; + } + return make_string_error(ctx, buf, err); +} + +static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *target; + int err; + + target = JS_ToCString(ctx, argv[0]); + if (!target) + return JS_EXCEPTION; + err = js_get_errno(chdir(target)); + JS_FreeCString(ctx, target); + return JS_NewInt32(ctx, err); +} + +static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int mode, ret; + const char *path; + + if (argc >= 2) { + if (JS_ToInt32(ctx, &mode, argv[1])) + return JS_EXCEPTION; + } else { + mode = 0777; + } + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; +#if defined(_WIN32) + (void)mode; + ret = js_get_errno(mkdir(path)); +#else + ret = js_get_errno(mkdir(path, mode)); +#endif + JS_FreeCString(ctx, path); + return JS_NewInt32(ctx, ret); +} + +/* return [array, errorcode] */ +static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ +#ifdef _WIN32 + const char *path; + JSValue obj; + int err; + uint32_t len; + HANDLE h; + WIN32_FIND_DATAA d; + char s[1024]; + + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) { + JS_FreeCString(ctx, path); + return JS_EXCEPTION; + } + snprintf(s, sizeof(s), "%s/*", path); + JS_FreeCString(ctx, path); + err = 0; + h = FindFirstFileA(s, &d); + if (h == INVALID_HANDLE_VALUE) + err = GetLastError(); + if (err) + goto done; + JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewString(ctx, "."), + JS_PROP_C_W_E); + for (len = 1; FindNextFileA(h, &d); len++) { + JS_DefinePropertyValueUint32(ctx, obj, len, + JS_NewString(ctx, d.cFileName), + JS_PROP_C_W_E); + } + FindClose(h); +done: + return make_obj_error(ctx, obj, err); +#else + const char *path; + DIR *f; + struct dirent *d; + JSValue obj; + int err; + uint32_t len; + + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) { + JS_FreeCString(ctx, path); + return JS_EXCEPTION; + } + f = opendir(path); + if (!f) + err = errno; + else + err = 0; + JS_FreeCString(ctx, path); + if (!f) + goto done; + len = 0; + for(;;) { + errno = 0; + d = readdir(f); + if (!d) { + err = errno; + break; + } + JS_DefinePropertyValueUint32(ctx, obj, len++, + JS_NewString(ctx, d->d_name), + JS_PROP_C_W_E); + } + closedir(f); + done: + return make_obj_error(ctx, obj, err); +#endif +} + +#if !defined(_WIN32) +static int64_t timespec_to_ms(const struct timespec *tv) +{ + return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000); +} +#endif + +/* return [obj, errcode] */ +static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int is_lstat) +{ + const char *path; + int err, res; + struct stat st; + JSValue obj; + + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; +#if defined(_WIN32) + res = stat(path, &st); +#else + if (is_lstat) + res = lstat(path, &st); + else + res = stat(path, &st); +#endif + err = (res < 0) ? errno : 0; + JS_FreeCString(ctx, path); + if (res < 0) { + obj = JS_NULL; + } else { + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) + return JS_EXCEPTION; + JS_DefinePropertyValueStr(ctx, obj, "dev", + JS_NewInt64(ctx, st.st_dev), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "ino", + JS_NewInt64(ctx, st.st_ino), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "mode", + JS_NewInt32(ctx, st.st_mode), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "nlink", + JS_NewInt64(ctx, st.st_nlink), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "uid", + JS_NewInt64(ctx, st.st_uid), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "gid", + JS_NewInt64(ctx, st.st_gid), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "rdev", + JS_NewInt64(ctx, st.st_rdev), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "size", + JS_NewInt64(ctx, st.st_size), + JS_PROP_C_W_E); +#if !defined(_WIN32) + JS_DefinePropertyValueStr(ctx, obj, "blocks", + JS_NewInt64(ctx, st.st_blocks), + JS_PROP_C_W_E); +#endif +#if defined(_WIN32) + JS_DefinePropertyValueStr(ctx, obj, "atime", + JS_NewInt64(ctx, (int64_t)st.st_atime * 1000), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "mtime", + JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "ctime", + JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000), + JS_PROP_C_W_E); +#elif defined(__APPLE__) + JS_DefinePropertyValueStr(ctx, obj, "atime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "mtime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_mtimespec)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "ctime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)), + JS_PROP_C_W_E); +#else + JS_DefinePropertyValueStr(ctx, obj, "atime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "mtime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_mtim)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "ctime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_ctim)), + JS_PROP_C_W_E); +#endif + } + return make_obj_error(ctx, obj, err); +} + +#if !defined(_WIN32) +static void ms_to_timeval(struct timeval *tv, uint64_t v) +{ + tv->tv_sec = v / 1000; + tv->tv_usec = (v % 1000) * 1000; +} +#endif + +static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *path; + int64_t atime, mtime; + int ret; + + if (JS_ToInt64(ctx, &atime, argv[1])) + return JS_EXCEPTION; + if (JS_ToInt64(ctx, &mtime, argv[2])) + return JS_EXCEPTION; + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; +#if defined(_WIN32) + { + struct _utimbuf times; + times.actime = atime / 1000; + times.modtime = mtime / 1000; + ret = js_get_errno(_utime(path, ×)); + } +#else + { + struct timeval times[2]; + ms_to_timeval(×[0], atime); + ms_to_timeval(×[1], mtime); + ret = js_get_errno(utimes(path, times)); + } +#endif + JS_FreeCString(ctx, path); + return JS_NewInt32(ctx, ret); +} + +/* sleep(delay_ms) */ +static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int64_t delay; + int ret; + + if (JS_ToInt64(ctx, &delay, argv[0])) + return JS_EXCEPTION; + if (delay < 0) + delay = 0; +#if defined(_WIN32) + { + if (delay > INT32_MAX) + delay = INT32_MAX; + Sleep(delay); + ret = 0; + } +#else + { + struct timespec ts; + + ts.tv_sec = delay / 1000; + ts.tv_nsec = (delay % 1000) * 1000000; + ret = js_get_errno(nanosleep(&ts, NULL)); + } +#endif + return JS_NewInt32(ctx, ret); +} + +#if defined(_WIN32) +static char *realpath(const char *path, char *buf) +{ + if (!_fullpath(buf, path, JS__PATH_MAX)) { + errno = ENOENT; + return NULL; + } else { + return buf; + } +} +#endif + +#if !defined(__wasi__) +/* return [path, errorcode] */ +static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *path; + char buf[JS__PATH_MAX], *res; + int err; + + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; + res = realpath(path, buf); + JS_FreeCString(ctx, path); + if (!res) { + buf[0] = '\0'; + err = errno; + } else { + err = 0; + } + return make_string_error(ctx, buf, err); +} +#endif + +#if !defined(_WIN32) && !defined(__wasi__) && !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) +static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *target, *linkpath; + int err; + + target = JS_ToCString(ctx, argv[0]); + if (!target) + return JS_EXCEPTION; + linkpath = JS_ToCString(ctx, argv[1]); + if (!linkpath) { + JS_FreeCString(ctx, target); + return JS_EXCEPTION; + } + err = js_get_errno(symlink(target, linkpath)); + JS_FreeCString(ctx, target); + JS_FreeCString(ctx, linkpath); + return JS_NewInt32(ctx, err); +} + +/* return [path, errorcode] */ +static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *path; + char buf[JS__PATH_MAX]; + int err; + ssize_t res; + + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; + res = readlink(path, buf, sizeof(buf) - 1); + if (res < 0) { + buf[0] = '\0'; + err = errno; + } else { + buf[res] = '\0'; + err = 0; + } + JS_FreeCString(ctx, path); + return make_string_error(ctx, buf, err); +} + +static char **build_envp(JSContext *ctx, JSValue obj) +{ + uint32_t len, i; + JSPropertyEnum *tab; + char **envp, *pair; + const char *key, *str; + JSValue val; + size_t key_len, str_len; + + if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj, + JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) + return NULL; + envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1)); + if (!envp) + goto fail; + for(i = 0; i < len; i++) { + val = JS_GetProperty(ctx, obj, tab[i].atom); + if (JS_IsException(val)) + goto fail; + str = JS_ToCString(ctx, val); + JS_FreeValue(ctx, val); + if (!str) + goto fail; + key = JS_AtomToCString(ctx, tab[i].atom); + if (!key) { + JS_FreeCString(ctx, str); + goto fail; + } + key_len = strlen(key); + str_len = strlen(str); + pair = js_malloc(ctx, key_len + str_len + 2); + if (!pair) { + JS_FreeCString(ctx, key); + JS_FreeCString(ctx, str); + goto fail; + } + memcpy(pair, key, key_len); + pair[key_len] = '='; + memcpy(pair + key_len + 1, str, str_len); + pair[key_len + 1 + str_len] = '\0'; + envp[i] = pair; + JS_FreeCString(ctx, key); + JS_FreeCString(ctx, str); + } + done: + for(i = 0; i < len; i++) + JS_FreeAtom(ctx, tab[i].atom); + js_free(ctx, tab); + return envp; + fail: + if (envp) { + for(i = 0; i < len; i++) + js_free(ctx, envp[i]); + js_free(ctx, envp); + envp = NULL; + } + goto done; +} + +/* execvpe is not available on non GNU systems */ +static int my_execvpe(const char *filename, char **argv, char **envp) +{ + char *path, *p, *p_next, *p1; + char buf[JS__PATH_MAX]; + size_t filename_len, path_len; + bool eacces_error; + + filename_len = strlen(filename); + if (filename_len == 0) { + errno = ENOENT; + return -1; + } + if (strchr(filename, '/')) + return execve(filename, argv, envp); + + path = getenv("PATH"); + if (!path) + path = (char *)"/bin:/usr/bin"; + eacces_error = false; + p = path; + for(p = path; p != NULL; p = p_next) { + p1 = strchr(p, ':'); + if (!p1) { + p_next = NULL; + path_len = strlen(p); + } else { + p_next = p1 + 1; + path_len = p1 - p; + } + /* path too long */ + if ((path_len + 1 + filename_len + 1) > JS__PATH_MAX) + continue; + memcpy(buf, p, path_len); + buf[path_len] = '/'; + memcpy(buf + path_len + 1, filename, filename_len); + buf[path_len + 1 + filename_len] = '\0'; + + execve(buf, argv, envp); + + switch(errno) { + case EACCES: + eacces_error = true; + break; + case ENOENT: + case ENOTDIR: + break; + default: + return -1; + } + } + if (eacces_error) + errno = EACCES; + return -1; +} + +static void (*js_os_exec_closefrom)(int); + +#if !defined(EMSCRIPTEN) && !defined(__wasi__) + +static js_once_t js_os_exec_once = JS_ONCE_INIT; + +static void js_os_exec_once_init(void) +{ + *(void **) (&js_os_exec_closefrom) = dlsym(RTLD_DEFAULT, "closefrom"); +} + +#endif + +/* exec(args[, options]) -> exitcode */ +static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValueConst options, args = argv[0]; + JSValue val, ret_val; + const char **exec_argv, *file = NULL, *str, *cwd = NULL; + char **envp = environ; + uint32_t exec_argc, i; + int ret, pid, status; + bool block_flag = true, use_path = true; + static const char *std_name[3] = { "stdin", "stdout", "stderr" }; + int std_fds[3]; + uint32_t uid = -1, gid = -1; + int ngroups = -1; + gid_t groups[64]; + + val = JS_GetPropertyStr(ctx, args, "length"); + if (JS_IsException(val)) + return JS_EXCEPTION; + ret = JS_ToUint32(ctx, &exec_argc, val); + JS_FreeValue(ctx, val); + if (ret) + return JS_EXCEPTION; + /* arbitrary limit to avoid overflow */ + if (exec_argc < 1 || exec_argc > 65535) { + return JS_ThrowTypeError(ctx, "invalid number of arguments"); + } + exec_argv = js_mallocz(ctx, sizeof(exec_argv[0]) * (exec_argc + 1)); + if (!exec_argv) + return JS_EXCEPTION; + for(i = 0; i < exec_argc; i++) { + val = JS_GetPropertyUint32(ctx, args, i); + if (JS_IsException(val)) + goto exception; + str = JS_ToCString(ctx, val); + JS_FreeValue(ctx, val); + if (!str) + goto exception; + exec_argv[i] = str; + } + exec_argv[exec_argc] = NULL; + + for(i = 0; i < 3; i++) + std_fds[i] = i; + + /* get the options, if any */ + if (argc >= 2) { + options = argv[1]; + + if (get_bool_option(ctx, &block_flag, options, "block")) + goto exception; + if (get_bool_option(ctx, &use_path, options, "usePath")) + goto exception; + + val = JS_GetPropertyStr(ctx, options, "file"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + file = JS_ToCString(ctx, val); + JS_FreeValue(ctx, val); + if (!file) + goto exception; + } + + val = JS_GetPropertyStr(ctx, options, "cwd"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + cwd = JS_ToCString(ctx, val); + JS_FreeValue(ctx, val); + if (!cwd) + goto exception; + } + + /* stdin/stdout/stderr handles */ + for(i = 0; i < 3; i++) { + val = JS_GetPropertyStr(ctx, options, std_name[i]); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + int fd; + ret = JS_ToInt32(ctx, &fd, val); + JS_FreeValue(ctx, val); + if (ret) + goto exception; + std_fds[i] = fd; + } + } + + val = JS_GetPropertyStr(ctx, options, "env"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + envp = build_envp(ctx, val); + JS_FreeValue(ctx, val); + if (!envp) + goto exception; + } + + val = JS_GetPropertyStr(ctx, options, "uid"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + ret = JS_ToUint32(ctx, &uid, val); + JS_FreeValue(ctx, val); + if (ret) + goto exception; + } + + val = JS_GetPropertyStr(ctx, options, "gid"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + ret = JS_ToUint32(ctx, &gid, val); + JS_FreeValue(ctx, val); + if (ret) + goto exception; + } + + val = JS_GetPropertyStr(ctx, options, "groups"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + int64_t idx, len; + JSValue prop; + uint32_t id; + ngroups = 0; + if (JS_GetLength(ctx, val, &len)) { + JS_FreeValue(ctx, val); + goto exception; + } + for (idx = 0; idx < len; idx++) { + prop = JS_GetPropertyInt64(ctx, val, idx); + if (JS_IsException(prop)) + break; + if (JS_IsUndefined(prop)) + continue; + ret = JS_ToUint32(ctx, &id, prop); + JS_FreeValue(ctx, prop); + if (ret) + break; + if (ngroups == countof(groups)) { + JS_ThrowRangeError(ctx, "too many groups"); + break; + } + groups[ngroups++] = id; + } + JS_FreeValue(ctx, val); + if (idx < len) + goto exception; + } + + } + +#if !defined(EMSCRIPTEN) && !defined(__wasi__) + // should happen pre-fork because it calls dlsym() + // and that's not an async-signal-safe function + js_once(&js_os_exec_once, js_os_exec_once_init); +#endif + + pid = fork(); + if (pid < 0) { + JS_ThrowTypeError(ctx, "fork error"); + goto exception; + } + if (pid == 0) { + /* child */ + /* remap the stdin/stdout/stderr handles if necessary */ + for(i = 0; i < 3; i++) { + if (std_fds[i] != i) { + if (dup2(std_fds[i], i) < 0) + _exit(127); + } + } + + if (js_os_exec_closefrom) { + js_os_exec_closefrom(3); + } else { + int fd_max = sysconf(_SC_OPEN_MAX); + for(i = 3; i < fd_max; i++) + close(i); + } + + if (cwd) { + if (chdir(cwd) < 0) + _exit(127); + } + if (ngroups != -1) { + if (setgroups(ngroups, groups) < 0) + _exit(127); + } + if (uid != -1) { + if (setuid(uid) < 0) + _exit(127); + } + if (gid != -1) { + if (setgid(gid) < 0) + _exit(127); + } + + if (!file) + file = exec_argv[0]; + if (use_path) + ret = my_execvpe(file, (char **)exec_argv, envp); + else + ret = execve(file, (char **)exec_argv, envp); + _exit(127); + } + /* parent */ + if (block_flag) { + for(;;) { + ret = waitpid(pid, &status, 0); + if (ret == pid) { + if (WIFEXITED(status)) { + ret = WEXITSTATUS(status); + break; + } else if (WIFSIGNALED(status)) { + ret = -WTERMSIG(status); + break; + } + } + } + } else { + ret = pid; + } + ret_val = JS_NewInt32(ctx, ret); + done: + JS_FreeCString(ctx, file); + JS_FreeCString(ctx, cwd); + for(i = 0; i < exec_argc; i++) + JS_FreeCString(ctx, exec_argv[i]); + js_free(ctx, exec_argv); + if (envp != environ) { + char **p; + p = envp; + while (*p != NULL) { + js_free(ctx, *p); + p++; + } + js_free(ctx, envp); + } + return ret_val; + exception: + ret_val = JS_EXCEPTION; + goto done; +} + +/* getpid() -> pid */ +static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + return JS_NewInt32(ctx, getpid()); +} + +/* waitpid(pid, block) -> [pid, status] */ +static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int pid, status, options, ret; + JSValue obj; + + if (JS_ToInt32(ctx, &pid, argv[0])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &options, argv[1])) + return JS_EXCEPTION; + + ret = waitpid(pid, &status, options); + if (ret < 0) { + ret = -errno; + status = 0; + } + + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) + return obj; + JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ret), + JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, status), + JS_PROP_C_W_E); + return obj; +} + +/* pipe() -> [read_fd, write_fd] or null if error */ +static JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int pipe_fds[2], ret; + JSValue obj; + + ret = pipe(pipe_fds); + if (ret < 0) + return JS_NULL; + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) + return obj; + JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, pipe_fds[0]), + JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, pipe_fds[1]), + JS_PROP_C_W_E); + return obj; +} + +/* kill(pid, sig) */ +static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int pid, sig, ret; + + if (JS_ToInt32(ctx, &pid, argv[0])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &sig, argv[1])) + return JS_EXCEPTION; + ret = js_get_errno(kill(pid, sig)); + return JS_NewInt32(ctx, ret); +} + +/* dup(fd) */ +static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd, ret; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + ret = js_get_errno(dup(fd)); + return JS_NewInt32(ctx, ret); +} + +/* dup2(fd) */ +static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd, fd2, ret; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &fd2, argv[1])) + return JS_EXCEPTION; + ret = js_get_errno(dup2(fd, fd2)); + return JS_NewInt32(ctx, ret); +} + +#endif /* !_WIN32 */ + +#ifdef USE_WORKER + +/* Worker */ + +typedef struct { + JSWorkerMessagePipe *recv_pipe; + JSWorkerMessagePipe *send_pipe; + JSWorkerMessageHandler *msg_handler; +} JSWorkerData; + +typedef struct { + char *filename; /* module filename */ + char *basename; /* module base name */ + JSWorkerMessagePipe *recv_pipe, *send_pipe; +} WorkerFuncArgs; + +typedef struct { + int ref_count; + uint64_t buf[]; +} JSSABHeader; + +static JSRuntime *(*js_worker_new_runtime_func)(void) = JS_NewRuntime; +static JSContext *(*js_worker_new_context_func)(JSRuntime *rt) = JS_NewContext; + +static int atomic_add_int(int *ptr, int v) +{ + return atomic_fetch_add((_Atomic uint32_t*)ptr, v) + v; +} + +/* shared array buffer allocator */ +static void *js_sab_alloc(void *opaque, size_t size) +{ + JSSABHeader *sab; + sab = malloc(sizeof(JSSABHeader) + size); + if (!sab) + return NULL; + sab->ref_count = 1; + return sab->buf; +} + +static void js_sab_free(void *opaque, void *ptr) +{ + JSSABHeader *sab; + int ref_count; + sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader)); + ref_count = atomic_add_int(&sab->ref_count, -1); + assert(ref_count >= 0); + if (ref_count == 0) { + free(sab); + } +} + +static void js_sab_dup(void *opaque, void *ptr) +{ + JSSABHeader *sab; + sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader)); + atomic_add_int(&sab->ref_count, 1); +} + +static JSWorkerMessagePipe *js_new_message_pipe(void) +{ + JSWorkerMessagePipe *ps; + + ps = malloc(sizeof(*ps)); + if (!ps) + return NULL; + if (js_waker_init(&ps->waker)) { + free(ps); + return NULL; + } + ps->ref_count = 1; + init_list_head(&ps->msg_queue); + js_mutex_init(&ps->mutex); + return ps; +} + +static JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps) +{ + atomic_add_int(&ps->ref_count, 1); + return ps; +} + +static void js_free_message(JSWorkerMessage *msg) +{ + size_t i; + /* free the SAB */ + for(i = 0; i < msg->sab_tab_len; i++) { + js_sab_free(NULL, msg->sab_tab[i]); + } + free(msg->sab_tab); + free(msg->data); + free(msg); +} + +static void js_free_message_pipe(JSWorkerMessagePipe *ps) +{ + struct list_head *el, *el1; + JSWorkerMessage *msg; + int ref_count; + + if (!ps) + return; + + ref_count = atomic_add_int(&ps->ref_count, -1); + assert(ref_count >= 0); + if (ref_count == 0) { + list_for_each_safe(el, el1, &ps->msg_queue) { + msg = list_entry(el, JSWorkerMessage, link); + js_free_message(msg); + } + js_mutex_destroy(&ps->mutex); + js_waker_close(&ps->waker); + free(ps); + } +} + +static void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port) +{ + if (port) { + js_free_message_pipe(port->recv_pipe); + JS_FreeValueRT(rt, port->on_message_func); + list_del(&port->link); + js_free_rt(rt, port); + } +} + +static void js_worker_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSThreadState *ts = js_get_thread_state(rt); + JSWorkerData *worker = JS_GetOpaque(val, ts->worker_class_id); + if (worker) { + js_free_message_pipe(worker->recv_pipe); + js_free_message_pipe(worker->send_pipe); + js_free_port(rt, worker->msg_handler); + js_free_rt(rt, worker); + } +} + +static JSClassDef js_worker_class = { + "Worker", + .finalizer = js_worker_finalizer, +}; + +static void worker_func(void *opaque) +{ + WorkerFuncArgs *args = opaque; + JSRuntime *rt; + JSThreadState *ts; + JSContext *ctx; + JSValue val; + + rt = js_worker_new_runtime_func(); + if (rt == NULL) { + fprintf(stderr, "JS_NewRuntime failure"); + exit(1); + } + js_std_init_handlers(rt); + + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); + + /* set the pipe to communicate with the parent */ + ts = js_get_thread_state(rt); + ts->recv_pipe = args->recv_pipe; + ts->send_pipe = args->send_pipe; + + /* function pointer to avoid linking the whole JS_NewContext() if + not needed */ + ctx = js_worker_new_context_func(rt); + if (ctx == NULL) { + fprintf(stderr, "JS_NewContext failure"); + } + + JS_SetCanBlock(rt, true); + + js_std_add_helpers(ctx, -1, NULL); + + val = JS_LoadModule(ctx, args->basename, args->filename); + free(args->filename); + free(args->basename); + free(args); + val = js_std_await(ctx, val); + if (JS_IsException(val)) + js_std_dump_error(ctx); + JS_FreeValue(ctx, val); + + js_std_loop(ctx); + + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + +static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target, + JSWorkerMessagePipe *recv_pipe, + JSWorkerMessagePipe *send_pipe) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSValue obj = JS_UNDEFINED, proto; + JSWorkerData *s; + + /* create the object */ + if (JS_IsUndefined(new_target)) { + proto = JS_GetClassProto(ctx, ts->worker_class_id); + } else { + proto = JS_GetPropertyStr(ctx, new_target, "prototype"); + if (JS_IsException(proto)) + goto fail; + } + obj = JS_NewObjectProtoClass(ctx, proto, ts->worker_class_id); + JS_FreeValue(ctx, proto); + if (JS_IsException(obj)) + goto fail; + s = js_mallocz(ctx, sizeof(*s)); + if (!s) + goto fail; + s->recv_pipe = js_dup_message_pipe(recv_pipe); + s->send_pipe = js_dup_message_pipe(send_pipe); + + JS_SetOpaque(obj, s); + return obj; + fail: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + WorkerFuncArgs *args = NULL; + js_thread_t thr; + JSValue obj = JS_UNDEFINED; + int ret; + const char *filename = NULL, *basename; + JSAtom basename_atom; + + /* XXX: in order to avoid problems with resource liberation, we + don't support creating workers inside workers */ + if (!is_main_thread(rt)) + return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker"); + + /* base name, assuming the calling function is a normal JS + function */ + basename_atom = JS_GetScriptOrModuleName(ctx, 1); + if (basename_atom == JS_ATOM_NULL) { + return JS_ThrowTypeError(ctx, "could not determine calling script or module name"); + } + basename = JS_AtomToCString(ctx, basename_atom); + JS_FreeAtom(ctx, basename_atom); + if (!basename) + goto fail; + + /* module name */ + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + goto fail; + + args = malloc(sizeof(*args)); + if (!args) + goto oom_fail; + memset(args, 0, sizeof(*args)); + args->filename = strdup(filename); + args->basename = strdup(basename); + + /* ports */ + args->recv_pipe = js_new_message_pipe(); + if (!args->recv_pipe) + goto oom_fail; + args->send_pipe = js_new_message_pipe(); + if (!args->send_pipe) + goto oom_fail; + + obj = js_worker_ctor_internal(ctx, new_target, + args->send_pipe, args->recv_pipe); + if (JS_IsException(obj)) + goto fail; + + ret = js_thread_create(&thr, worker_func, args, JS_THREAD_CREATE_DETACHED); + if (ret != 0) { + JS_ThrowTypeError(ctx, "could not create worker"); + goto fail; + } + JS_FreeCString(ctx, basename); + JS_FreeCString(ctx, filename); + return obj; + oom_fail: + JS_ThrowOutOfMemory(ctx); + fail: + JS_FreeCString(ctx, basename); + JS_FreeCString(ctx, filename); + if (args) { + free(args->filename); + free(args->basename); + js_free_message_pipe(args->recv_pipe); + js_free_message_pipe(args->send_pipe); + free(args); + } + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, ts->worker_class_id); + JSWorkerMessagePipe *ps; + size_t data_len, i; + uint8_t *data; + JSWorkerMessage *msg; + JSSABTab sab_tab; + + if (!worker) + return JS_EXCEPTION; + + data = JS_WriteObject2(ctx, &data_len, argv[0], + JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE, + &sab_tab); + if (!data) + return JS_EXCEPTION; + + msg = malloc(sizeof(*msg)); + if (!msg) + goto fail; + msg->data = NULL; + msg->sab_tab = NULL; + + /* must reallocate because the allocator may be different */ + msg->data = malloc(data_len); + if (!msg->data) + goto fail; + memcpy(msg->data, data, data_len); + msg->data_len = data_len; + + if (sab_tab.len > 0) { + msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab.len); + if (!msg->sab_tab) + goto fail; + memcpy(msg->sab_tab, sab_tab.tab, sizeof(msg->sab_tab[0]) * sab_tab.len); + } + msg->sab_tab_len = sab_tab.len; + + js_free(ctx, data); + js_free(ctx, sab_tab.tab); + + /* increment the SAB reference counts */ + for(i = 0; i < msg->sab_tab_len; i++) { + js_sab_dup(NULL, msg->sab_tab[i]); + } + + ps = worker->send_pipe; + js_mutex_lock(&ps->mutex); + /* indicate that data is present */ + if (list_empty(&ps->msg_queue)) + js_waker_signal(&ps->waker); + list_add_tail(&msg->link, &ps->msg_queue); + js_mutex_unlock(&ps->mutex); + return JS_UNDEFINED; + fail: + if (msg) { + free(msg->data); + free(msg->sab_tab); + free(msg); + } + js_free(ctx, data); + js_free(ctx, sab_tab.tab); + return JS_EXCEPTION; + +} + +static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val, + JSValueConst func) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, ts->worker_class_id); + JSWorkerMessageHandler *port; + + if (!worker) + return JS_EXCEPTION; + + port = worker->msg_handler; + if (JS_IsNull(func)) { + if (port) { + js_free_port(rt, port); + worker->msg_handler = NULL; + } + } else { + if (!JS_IsFunction(ctx, func)) + return JS_ThrowTypeError(ctx, "not a function"); + if (!port) { + port = js_mallocz(ctx, sizeof(*port)); + if (!port) + return JS_EXCEPTION; + port->recv_pipe = js_dup_message_pipe(worker->recv_pipe); + port->on_message_func = JS_NULL; + list_add_tail(&port->link, &ts->port_list); + worker->msg_handler = port; + } + JS_FreeValue(ctx, port->on_message_func); + port->on_message_func = JS_DupValue(ctx, func); + } + return JS_UNDEFINED; +} + +static JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, ts->worker_class_id); + JSWorkerMessageHandler *port; + if (!worker) + return JS_EXCEPTION; + port = worker->msg_handler; + if (port) { + return JS_DupValue(ctx, port->on_message_func); + } else { + return JS_NULL; + } +} + +static const JSCFunctionListEntry js_worker_proto_funcs[] = { + JS_CFUNC_DEF("postMessage", 1, js_worker_postMessage ), + JS_CGETSET_DEF("onmessage", js_worker_get_onmessage, js_worker_set_onmessage ), +}; + +#endif /* USE_WORKER */ + +void js_std_set_worker_new_runtime_func(JSRuntime *(*func)(void)) +{ +#ifdef USE_WORKER + js_worker_new_runtime_func = func; +#endif +} + +void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)) +{ +#ifdef USE_WORKER + js_worker_new_context_func = func; +#endif +} + +#if defined(_WIN32) +#define OS_PLATFORM "win32" +#elif defined(__APPLE__) +#define OS_PLATFORM "darwin" +#elif defined(EMSCRIPTEN) +#define OS_PLATFORM "js" +#elif defined(__CYGWIN__) +#define OS_PLATFORM "cygwin" +#elif defined(__linux__) +#define OS_PLATFORM "linux" +#elif defined(__OpenBSD__) +#define OS_PLATFORM "openbsd" +#elif defined(__NetBSD__) +#define OS_PLATFORM "netbsd" +#elif defined(__FreeBSD__) +#define OS_PLATFORM "freebsd" +#elif defined(__wasi__) +#define OS_PLATFORM "wasi" +#elif defined(__GNU__) +#define OS_PLATFORM "hurd" +#else +#define OS_PLATFORM "unknown" +#endif + +#define OS_FLAG(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE ) + +static const JSCFunctionListEntry js_os_funcs[] = { + JS_CFUNC_DEF("open", 2, js_os_open ), + OS_FLAG(O_RDONLY), + OS_FLAG(O_WRONLY), + OS_FLAG(O_RDWR), + OS_FLAG(O_APPEND), + OS_FLAG(O_CREAT), + OS_FLAG(O_EXCL), + OS_FLAG(O_TRUNC), +#if defined(_WIN32) + OS_FLAG(O_BINARY), + OS_FLAG(O_TEXT), +#endif + JS_CFUNC_DEF("close", 1, js_os_close ), + JS_CFUNC_DEF("seek", 3, js_os_seek ), + JS_CFUNC_MAGIC_DEF("read", 4, js_os_read_write, 0 ), + JS_CFUNC_MAGIC_DEF("write", 4, js_os_read_write, 1 ), + JS_CFUNC_DEF("isatty", 1, js_os_isatty ), +#if !defined(__wasi__) + JS_CFUNC_DEF("ttyGetWinSize", 1, js_os_ttyGetWinSize ), + JS_CFUNC_DEF("ttySetRaw", 1, js_os_ttySetRaw ), +#endif + JS_CFUNC_DEF("remove", 1, js_os_remove ), + JS_CFUNC_DEF("rename", 2, js_os_rename ), + JS_CFUNC_MAGIC_DEF("setReadHandler", 2, js_os_setReadHandler, 0 ), + JS_CFUNC_MAGIC_DEF("setWriteHandler", 2, js_os_setReadHandler, 1 ), + JS_CFUNC_DEF("signal", 2, js_os_signal ), + OS_FLAG(SIGINT), + OS_FLAG(SIGABRT), + OS_FLAG(SIGFPE), + OS_FLAG(SIGILL), + OS_FLAG(SIGSEGV), + OS_FLAG(SIGTERM), +#if !defined(_WIN32) && !defined(__wasi__) + OS_FLAG(SIGQUIT), + OS_FLAG(SIGPIPE), + OS_FLAG(SIGALRM), + OS_FLAG(SIGUSR1), + OS_FLAG(SIGUSR2), + OS_FLAG(SIGCHLD), + OS_FLAG(SIGCONT), + OS_FLAG(SIGSTOP), + OS_FLAG(SIGTSTP), + OS_FLAG(SIGTTIN), + OS_FLAG(SIGTTOU), + JS_CFUNC_DEF("cputime", 0, js_os_cputime ), +#endif + JS_CFUNC_DEF("exePath", 0, js_os_exepath ), + JS_CFUNC_DEF("now", 0, js_os_now ), + JS_CFUNC_MAGIC_DEF("setTimeout", 2, js_os_setTimeout, 0 ), + JS_CFUNC_MAGIC_DEF("setInterval", 2, js_os_setTimeout, 1 ), + // per spec: both functions can cancel timeouts and intervals + JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ), + JS_CFUNC_DEF("clearInterval", 1, js_os_clearTimeout ), + JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ), + JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ), + JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ), + JS_CFUNC_DEF("chdir", 0, js_os_chdir ), + JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ), + JS_CFUNC_DEF("readdir", 1, js_os_readdir ), + /* st_mode constants */ + OS_FLAG(S_IFMT), + OS_FLAG(S_IFIFO), + OS_FLAG(S_IFCHR), + OS_FLAG(S_IFDIR), + OS_FLAG(S_IFBLK), + OS_FLAG(S_IFREG), +#if !defined(_WIN32) + OS_FLAG(S_IFSOCK), + OS_FLAG(S_IFLNK), + OS_FLAG(S_ISGID), + OS_FLAG(S_ISUID), +#endif + JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ), + JS_CFUNC_DEF("utimes", 3, js_os_utimes ), + JS_CFUNC_DEF("sleep", 1, js_os_sleep ), +#if !defined(__wasi__) + JS_CFUNC_DEF("realpath", 1, js_os_realpath ), +#endif +#if !defined(_WIN32) && !defined(__wasi__) && !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) + JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ), + JS_CFUNC_DEF("symlink", 2, js_os_symlink ), + JS_CFUNC_DEF("readlink", 1, js_os_readlink ), + JS_CFUNC_DEF("exec", 1, js_os_exec ), + JS_CFUNC_DEF("getpid", 0, js_os_getpid ), + JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ), + OS_FLAG(WNOHANG), + JS_CFUNC_DEF("pipe", 0, js_os_pipe ), + JS_CFUNC_DEF("kill", 2, js_os_kill ), + JS_CFUNC_DEF("dup", 1, js_os_dup ), + JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), +#endif +}; + +static int js_os_init(JSContext *ctx, JSModuleDef *m) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + + ts->can_js_os_poll = true; + +#ifdef USE_WORKER + { + JSValue proto, obj; + /* Worker class */ + JS_NewClassID(rt, &ts->worker_class_id); + JS_NewClass(rt, ts->worker_class_id, &js_worker_class); + proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs)); + + obj = JS_NewCFunction2(ctx, js_worker_ctor, "Worker", 1, + JS_CFUNC_constructor, 0); + JS_SetConstructor(ctx, obj, proto); + + JS_SetClassProto(ctx, ts->worker_class_id, proto); + + /* set 'Worker.parent' if necessary */ + if (ts->recv_pipe && ts->send_pipe) { + JS_DefinePropertyValueStr(ctx, obj, "parent", + js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe), + JS_PROP_C_W_E); + } + + JS_SetModuleExport(ctx, m, "Worker", obj); + } +#endif /* USE_WORKER */ + + return JS_SetModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs)); +} + +JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_os_init); + if (!m) + return NULL; + JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs)); +#ifdef USE_WORKER + JS_AddModuleExport(ctx, m, "Worker"); +#endif + return m; +} + +/**********************************************************/ + +static JSValue js_print(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ +#ifdef _WIN32 + HANDLE handle; + DWORD mode; +#endif + const char *s; + JSValueConst v; + DynBuf b; + int i; + + dbuf_init(&b); + for(i = 0; i < argc; i++) { + v = argv[i]; + s = JS_ToCString(ctx, v); + if (!s && JS_IsObject(v)) { + JS_FreeValue(ctx, JS_GetException(ctx)); + JSValue t = JS_ToObjectString(ctx, v); + s = JS_ToCString(ctx, t); + JS_FreeValue(ctx, t); + } + if (s) { + dbuf_printf(&b, "%s%s", &" "[!i], s); + JS_FreeCString(ctx, s); + } else { + dbuf_printf(&b, "%s", &" "[!i]); + JS_FreeValue(ctx, JS_GetException(ctx)); + } + } + dbuf_putc(&b, '\n'); +#ifdef _WIN32 + // use WriteConsoleA with CP_UTF8 for better Unicode handling vis-a-vis + // the mangling that happens when going through msvcrt's stdio layer, + // *except* when stdout is redirected to something that is not a console + handle = (HANDLE)_get_osfhandle(/*STDOUT_FILENO*/1); // don't CloseHandle + if (GetFileType(handle) != FILE_TYPE_CHAR) + goto fallback; + if (!GetConsoleMode(handle, &mode)) + goto fallback; + handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (handle == INVALID_HANDLE_VALUE) + goto fallback; + mode = GetConsoleOutputCP(); + SetConsoleOutputCP(CP_UTF8); + WriteConsoleA(handle, b.buf, b.size, NULL, NULL); + SetConsoleOutputCP(mode); + FlushFileBuffers(handle); + goto done; +fallback: +#endif + fwrite(b.buf, 1, b.size, stdout); + fflush(stdout); + goto done; // avoid unused label warning +done: + dbuf_free(&b); + return JS_UNDEFINED; +} + +void js_std_add_helpers(JSContext *ctx, int argc, char **argv) +{ + JSValue global_obj, console, args; + int i; + + /* XXX: should these global definitions be enumerable? */ + global_obj = JS_GetGlobalObject(ctx); + + console = JS_NewObject(ctx); + JS_SetPropertyStr(ctx, console, "log", + JS_NewCFunction(ctx, js_print, "log", 1)); + JS_SetPropertyStr(ctx, global_obj, "console", console); + + /* same methods as the mozilla JS shell */ + if (argc >= 0) { + args = JS_NewArray(ctx); + for(i = 0; i < argc; i++) { + JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i])); + } + JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args); + } + + JS_SetPropertyStr(ctx, global_obj, "print", + JS_NewCFunction(ctx, js_print, "print", 1)); + + JS_FreeValue(ctx, global_obj); +} + +static void js_std_finalize(JSRuntime *rt, void *arg) +{ + JSThreadState *ts = arg; + js_set_thread_state(rt, NULL); + js_free_rt(rt, ts); +} + +void js_std_init_handlers(JSRuntime *rt) +{ + JSThreadState *ts; + + ts = js_mallocz_rt(rt, sizeof(*ts)); + if (!ts) { + fprintf(stderr, "Could not allocate memory for the worker"); + exit(1); + } + init_list_head(&ts->os_rw_handlers); + init_list_head(&ts->os_signal_handlers); + init_list_head(&ts->os_timers); + init_list_head(&ts->port_list); + init_list_head(&ts->rejected_promise_list); + + ts->next_timer_id = 1; + + js_set_thread_state(rt, ts); + JS_AddRuntimeFinalizer(rt, js_std_finalize, ts); + +#ifdef USE_WORKER + /* set the SharedArrayBuffer memory handlers */ + { + JSSharedArrayBufferFunctions sf; + memset(&sf, 0, sizeof(sf)); + sf.sab_alloc = js_sab_alloc; + sf.sab_free = js_sab_free; + sf.sab_dup = js_sab_dup; + JS_SetSharedArrayBufferFunctions(rt, &sf); + } +#endif +} + +static void free_rp(JSRuntime *rt, JSRejectedPromiseEntry *rp) +{ + list_del(&rp->link); + JS_FreeValueRT(rt, rp->promise); + JS_FreeValueRT(rt, rp->reason); + js_free_rt(rt, rp); +} + +void js_std_free_handlers(JSRuntime *rt) +{ + JSThreadState *ts = js_get_thread_state(rt); + struct list_head *el, *el1; + + list_for_each_safe(el, el1, &ts->os_rw_handlers) { + JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link); + free_rw_handler(rt, rh); + } + + list_for_each_safe(el, el1, &ts->os_signal_handlers) { + JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link); + free_sh(rt, sh); + } + + list_for_each_safe(el, el1, &ts->os_timers) { + JSOSTimer *th = list_entry(el, JSOSTimer, link); + free_timer(rt, th); + } + + list_for_each_safe(el, el1, &ts->rejected_promise_list) { + JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link); + free_rp(rt, rp); + } + +#ifdef USE_WORKER + /* XXX: free port_list ? */ + js_free_message_pipe(ts->recv_pipe); + js_free_message_pipe(ts->send_pipe); +#endif +} + +static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val) +{ + const char *str; + + str = JS_ToCString(ctx, val); + if (str) { + fprintf(f, "%s\n", str); + JS_FreeCString(ctx, str); + } else { + fprintf(f, "[exception]\n"); + } +} + +static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val) +{ + JSValue val; + bool is_error; + + is_error = JS_IsError(exception_val); + js_dump_obj(ctx, stderr, exception_val); + if (is_error) { + val = JS_GetPropertyStr(ctx, exception_val, "stack"); + } else { + js_std_cmd(/*ErrorBackTrace*/2, ctx, &val); + } + if (!JS_IsUndefined(val)) { + js_dump_obj(ctx, stderr, val); + JS_FreeValue(ctx, val); + } +} + +void js_std_dump_error(JSContext *ctx) +{ + JSValue exception_val; + + exception_val = JS_GetException(ctx); + js_std_dump_error1(ctx, exception_val); + JS_FreeValue(ctx, exception_val); +} + +static JSRejectedPromiseEntry *find_rejected_promise(JSContext *ctx, JSThreadState *ts, + JSValueConst promise) +{ + struct list_head *el; + + list_for_each(el, &ts->rejected_promise_list) { + JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link); + if (JS_IsSameValue(ctx, rp->promise, promise)) + return rp; + } + return NULL; +} + +void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, + JSValueConst reason, + bool is_handled, void *opaque) +{ + + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSRejectedPromiseEntry *rp = find_rejected_promise(ctx, ts, promise); + + if (is_handled) { + /* the rejection is handled, so the entry can be removed if present */ + if (rp) + free_rp(rt, rp); + } else { + /* add a new entry if needed */ + if (!rp) { + rp = js_malloc_rt(rt, sizeof(*rp)); + if (rp) { + rp->promise = JS_DupValue(ctx, promise); + rp->reason = JS_DupValue(ctx, reason); + list_add_tail(&rp->link, &ts->rejected_promise_list); + } + } + } +} + +/* check if there are pending promise rejections. It must be done + asynchrously in case a rejected promise is handled later. Currently + we do it once the application is about to sleep. It could be done + more often if needed. */ +static void js_std_promise_rejection_check(JSContext *ctx) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + struct list_head *el; + + if (unlikely(!list_empty(&ts->rejected_promise_list))) { + list_for_each(el, &ts->rejected_promise_list) { + JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link); + fprintf(stderr, "Possibly unhandled promise rejection: "); + js_std_dump_error1(ctx, rp->reason); + fflush(stderr); + } + exit(1); + } +} + +/* main loop which calls the user JS callbacks */ +int js_std_loop(JSContext *ctx) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSContext *ctx1; + int err; + + for(;;) { + /* execute the pending jobs */ + for(;;) { + err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + if (err <= 0) { + if (err < 0) + goto done; + break; + } + } + + js_std_promise_rejection_check(ctx); + + if (!ts->can_js_os_poll || js_os_poll(ctx)) + break; + } +done: + return JS_HasException(ctx); +} + +/* Wait for a promise and execute pending jobs while waiting for + it. Return the promise result or JS_EXCEPTION in case of promise + rejection. */ +JSValue js_std_await(JSContext *ctx, JSValue obj) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + JSValue ret; + int state; + + for(;;) { + state = JS_PromiseState(ctx, obj); + if (state == JS_PROMISE_FULFILLED) { + ret = JS_PromiseResult(ctx, obj); + JS_FreeValue(ctx, obj); + break; + } else if (state == JS_PROMISE_REJECTED) { + ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj)); + JS_FreeValue(ctx, obj); + break; + } else if (state == JS_PROMISE_PENDING) { + JSContext *ctx1; + int err; + err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + if (err < 0) { + js_std_dump_error(ctx1); + } + if (err == 0) + js_std_promise_rejection_check(ctx); + if (ts->can_js_os_poll) + js_os_poll(ctx); + } else { + /* not a promise */ + ret = obj; + break; + } + } + return ret; +} + +void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, + int load_only) +{ + JSValue obj, val; + obj = JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE); + if (JS_IsException(obj)) + goto exception; + if (load_only) { + if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { + if (js_module_set_import_meta(ctx, obj, false, false) < 0) + goto exception; + } + JS_FreeValue(ctx, obj); + } else { + if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { + if (JS_ResolveModule(ctx, obj) < 0) { + JS_FreeValue(ctx, obj); + goto exception; + } + if (js_module_set_import_meta(ctx, obj, false, true) < 0) + goto exception; + val = JS_EvalFunction(ctx, obj); + val = js_std_await(ctx, val); + } else { + val = JS_EvalFunction(ctx, obj); + } + if (JS_IsException(val)) { + exception: + js_std_dump_error(ctx); + exit(1); + } + JS_FreeValue(ctx, val); + } +} + +static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + uint8_t *buf; + uint64_t pos, len; + JSValue obj; + size_t size; + int flags; + + if (JS_ToIndex(ctx, &pos, argv[1])) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &len, argv[2])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &flags, argv[3])) + return JS_EXCEPTION; + buf = JS_GetArrayBuffer(ctx, &size, argv[0]); + if (!buf) + return JS_EXCEPTION; + if (pos + len > size) + return JS_ThrowRangeError(ctx, "array buffer overflow"); + obj = JS_ReadObject(ctx, buf + pos, len, flags); + return obj; +} + +static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + size_t len; + uint8_t *buf; + JSValue array; + int flags; + + if (JS_ToInt32(ctx, &flags, argv[1])) + return JS_EXCEPTION; + buf = JS_WriteObject(ctx, &len, argv[0], flags); + if (!buf) + return JS_EXCEPTION; + array = JS_NewArrayBufferCopy(ctx, buf, len); + js_free(ctx, buf); + return array; +} + + +static const JSCFunctionListEntry js_bjson_funcs[] = { + JS_CFUNC_DEF("read", 4, js_bjson_read ), + JS_CFUNC_DEF("write", 2, js_bjson_write ), +#define DEF(x) JS_PROP_INT32_DEF(#x, JS_##x, JS_PROP_CONFIGURABLE) + DEF(READ_OBJ_BYTECODE), + DEF(READ_OBJ_REFERENCE), + DEF(READ_OBJ_SAB), + DEF(WRITE_OBJ_BYTECODE), + DEF(WRITE_OBJ_REFERENCE), + DEF(WRITE_OBJ_SAB), + DEF(WRITE_OBJ_STRIP_DEBUG), + DEF(WRITE_OBJ_STRIP_SOURCE), +#undef DEF +}; + +static int js_bjson_init(JSContext *ctx, JSModuleDef *m) +{ + return JS_SetModuleExportList(ctx, m, js_bjson_funcs, + countof(js_bjson_funcs)); +} + +JSModuleDef *js_init_module_bjson(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_bjson_init); + if (!m) + return NULL; + JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs)); + return m; +} diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-libc.h b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-libc.h new file mode 100644 index 0000000..8617700 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-libc.h @@ -0,0 +1,81 @@ +/* + * QuickJS C library + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QUICKJS_LIBC_H +#define QUICKJS_LIBC_H + +#include +#include +#include + +#include "quickjs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define JS_EXTERN __attribute__((visibility("default"))) +#else +#define JS_EXTERN /* nothing */ +#endif + +JS_EXTERN JSModuleDef *js_init_module_std(JSContext *ctx, + const char *module_name); +JS_EXTERN JSModuleDef *js_init_module_os(JSContext *ctx, + const char *module_name); +JS_EXTERN JSModuleDef *js_init_module_bjson(JSContext *ctx, + const char *module_name); +JS_EXTERN void js_std_add_helpers(JSContext *ctx, int argc, char **argv); +JS_EXTERN int js_std_loop(JSContext *ctx); +JS_EXTERN JSValue js_std_await(JSContext *ctx, JSValue obj); +JS_EXTERN void js_std_init_handlers(JSRuntime *rt); +JS_EXTERN void js_std_free_handlers(JSRuntime *rt); +JS_EXTERN void js_std_dump_error(JSContext *ctx); +JS_EXTERN uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, + const char *filename); +JS_EXTERN int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, + bool use_realpath, bool is_main); +JS_EXTERN JSModuleDef *js_module_loader(JSContext *ctx, + const char *module_name, void *opaque); +JS_EXTERN void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, + size_t buf_len, int flags); +JS_EXTERN void js_std_promise_rejection_tracker(JSContext *ctx, + JSValueConst promise, + JSValueConst reason, + bool is_handled, + void *opaque); +// Defaults to JS_NewRuntime, no-op if compiled without worker support. +// Call before creating the first worker thread. +JS_EXTERN void js_std_set_worker_new_runtime_func(JSRuntime *(*func)(void)); +// Defaults to JS_NewContext, no-op if compiled without worker support. +// Call before creating the first worker thread. +JS_EXTERN void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); + +#undef JS_EXTERN + +#ifdef __cplusplus +} /* extern "C" { */ +#endif + +#endif /* QUICKJS_LIBC_H */ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-opcode.h b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-opcode.h new file mode 100644 index 0000000..bd5be75 --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs-opcode.h @@ -0,0 +1,371 @@ +/* + * QuickJS opcode definitions + * + * Copyright (c) 2017-2018 Fabrice Bellard + * Copyright (c) 2017-2018 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifdef FMT +FMT(none) +FMT(none_int) +FMT(none_loc) +FMT(none_arg) +FMT(none_var_ref) +FMT(u8) +FMT(i8) +FMT(loc8) +FMT(const8) +FMT(label8) +FMT(u16) +FMT(i16) +FMT(label16) +FMT(npop) +FMT(npopx) +FMT(npop_u16) +FMT(loc) +FMT(arg) +FMT(var_ref) +FMT(u32) +FMT(u32x2) +FMT(i32) +FMT(const) +FMT(label) +FMT(atom) +FMT(atom_u8) +FMT(atom_u16) +FMT(atom_label_u8) +FMT(atom_label_u16) +FMT(label_u16) +#undef FMT +#endif /* FMT */ + +#ifdef DEF + +#ifndef def +#define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f) +#endif + +DEF(invalid, 1, 0, 0, none) /* never emitted */ + +/* push values */ +DEF( push_i32, 5, 0, 1, i32) +DEF( push_const, 5, 0, 1, const) +DEF( fclosure, 5, 0, 1, const) /* must follow push_const */ +DEF(push_atom_value, 5, 0, 1, atom) +DEF( private_symbol, 5, 0, 1, atom) +DEF( undefined, 1, 0, 1, none) +DEF( null, 1, 0, 1, none) +DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */ +DEF( push_false, 1, 0, 1, none) +DEF( push_true, 1, 0, 1, none) +DEF( object, 1, 0, 1, none) +DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */ +DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */ + +DEF( drop, 1, 1, 0, none) /* a -> */ +DEF( nip, 1, 2, 1, none) /* a b -> b */ +DEF( nip1, 1, 3, 2, none) /* a b c -> b c */ +DEF( dup, 1, 1, 2, none) /* a -> a a */ +DEF( dup1, 1, 2, 3, none) /* a b -> a a b */ +DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */ +DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */ +DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */ +DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */ +DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */ +DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */ +DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */ +DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */ +DEF( swap, 1, 2, 2, none) /* a b -> b a */ +DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */ +DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */ +DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */ +DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */ +DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */ + +DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */ +DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */ +DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */ +DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */ +DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */ +DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */ +DEF( apply, 3, 3, 1, u16) +DEF( return, 1, 1, 0, none) +DEF( return_undef, 1, 0, 0, none) +DEF(check_ctor_return, 1, 1, 2, none) +DEF( check_ctor, 1, 0, 0, none) +DEF( init_ctor, 1, 0, 1, none) +DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */ +DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */ +DEF( return_async, 1, 1, 0, none) +DEF( throw, 1, 1, 0, none) +DEF( throw_error, 6, 0, 0, atom_u8) +DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */ +DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */ +DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a + bytecode string */ +DEF( get_super, 1, 1, 1, none) +DEF( import, 1, 1, 1, none) /* dynamic module import */ + +DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */ +DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */ +DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */ +DEF( put_var, 5, 1, 0, atom) /* must come after get_var */ +DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */ +DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */ + +DEF( get_ref_value, 1, 2, 3, none) +DEF( put_ref_value, 1, 3, 0, none) + +DEF( define_var, 6, 0, 0, atom_u8) +DEF(check_define_var, 6, 0, 0, atom_u8) +DEF( define_func, 6, 1, 0, atom_u8) + +// order matters, see IC counterparts +DEF( get_field, 5, 1, 1, atom) +DEF( get_field2, 5, 1, 2, atom) +DEF( put_field, 5, 2, 0, atom) + +DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */ +DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */ +DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */ +DEF( get_array_el, 1, 2, 1, none) +DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */ +DEF( put_array_el, 1, 3, 0, none) +DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */ +DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */ +DEF( define_field, 5, 2, 1, atom) +DEF( set_name, 5, 1, 1, atom) +DEF(set_name_computed, 1, 2, 2, none) +DEF( set_proto, 1, 2, 1, none) +DEF(set_home_object, 1, 2, 2, none) +DEF(define_array_el, 1, 3, 2, none) +DEF( append, 1, 3, 2, none) /* append enumerated object, update length */ +DEF(copy_data_properties, 2, 3, 3, u8) +DEF( define_method, 6, 2, 1, atom_u8) +DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */ +DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */ +DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */ + +DEF( get_loc, 3, 0, 1, loc) +DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */ +DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */ +DEF( get_arg, 3, 0, 1, arg) +DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */ +DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */ +DEF( get_var_ref, 3, 0, 1, var_ref) +DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */ +DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */ +DEF(set_loc_uninitialized, 3, 0, 0, loc) +DEF( get_loc_check, 3, 0, 1, loc) +DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ +DEF( put_loc_check_init, 3, 1, 0, loc) +DEF(get_var_ref_check, 3, 0, 1, var_ref) +DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ +DEF(put_var_ref_check_init, 3, 1, 0, var_ref) +DEF( close_loc, 3, 0, 0, loc) +DEF( if_false, 5, 1, 0, label) +DEF( if_true, 5, 1, 0, label) /* must come after if_false */ +DEF( goto, 5, 0, 0, label) /* must come after if_true */ +DEF( catch, 5, 0, 1, label) +DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */ +DEF( ret, 1, 1, 0, none) /* used to return from the finally block */ +DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */ + +DEF( to_object, 1, 1, 1, none) +//DEF( to_string, 1, 1, 1, none) +DEF( to_propkey, 1, 1, 1, none) +DEF( to_propkey2, 1, 2, 2, none) + +DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ +DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */ +DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ +DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ +DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ +DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8) + +DEF( make_loc_ref, 7, 0, 2, atom_u16) +DEF( make_arg_ref, 7, 0, 2, atom_u16) +DEF(make_var_ref_ref, 7, 0, 2, atom_u16) +DEF( make_var_ref, 5, 0, 2, atom) + +DEF( for_in_start, 1, 1, 1, none) +DEF( for_of_start, 1, 1, 3, none) +DEF(for_await_of_start, 1, 1, 3, none) +DEF( for_in_next, 1, 1, 3, none) +DEF( for_of_next, 2, 3, 5, u8) +DEF(iterator_check_object, 1, 1, 1, none) +DEF(iterator_get_value_done, 1, 1, 2, none) +DEF( iterator_close, 1, 3, 0, none) +DEF( iterator_next, 1, 4, 4, none) +DEF( iterator_call, 2, 4, 5, u8) +DEF( initial_yield, 1, 0, 0, none) +DEF( yield, 1, 1, 2, none) +DEF( yield_star, 1, 1, 2, none) +DEF(async_yield_star, 1, 1, 2, none) +DEF( await, 1, 1, 1, none) + +/* arithmetic/logic operations */ +DEF( neg, 1, 1, 1, none) +DEF( plus, 1, 1, 1, none) +DEF( dec, 1, 1, 1, none) +DEF( inc, 1, 1, 1, none) +DEF( post_dec, 1, 1, 2, none) +DEF( post_inc, 1, 1, 2, none) +DEF( dec_loc, 2, 0, 0, loc8) +DEF( inc_loc, 2, 0, 0, loc8) +DEF( add_loc, 2, 1, 0, loc8) +DEF( not, 1, 1, 1, none) +DEF( lnot, 1, 1, 1, none) +DEF( typeof, 1, 1, 1, none) +DEF( delete, 1, 2, 1, none) +DEF( delete_var, 5, 0, 1, atom) + +/* warning: order matters (see js_parse_assign_expr) */ +DEF( mul, 1, 2, 1, none) +DEF( div, 1, 2, 1, none) +DEF( mod, 1, 2, 1, none) +DEF( add, 1, 2, 1, none) +DEF( sub, 1, 2, 1, none) +DEF( shl, 1, 2, 1, none) +DEF( sar, 1, 2, 1, none) +DEF( shr, 1, 2, 1, none) +DEF( and, 1, 2, 1, none) +DEF( xor, 1, 2, 1, none) +DEF( or, 1, 2, 1, none) +DEF( pow, 1, 2, 1, none) + +DEF( lt, 1, 2, 1, none) +DEF( lte, 1, 2, 1, none) +DEF( gt, 1, 2, 1, none) +DEF( gte, 1, 2, 1, none) +DEF( instanceof, 1, 2, 1, none) +DEF( in, 1, 2, 1, none) +DEF( eq, 1, 2, 1, none) +DEF( neq, 1, 2, 1, none) +DEF( strict_eq, 1, 2, 1, none) +DEF( strict_neq, 1, 2, 1, none) +DEF(is_undefined_or_null, 1, 1, 1, none) +DEF( private_in, 1, 2, 1, none) +DEF(push_bigint_i32, 5, 0, 1, i32) +/* must be the last non short and non temporary opcode */ +DEF( nop, 1, 0, 0, none) + +/* temporary opcodes: never emitted in the final bytecode */ + +def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ +def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ + +def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */ + +def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ +def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ +def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ +def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ +def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ +def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ +def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ +def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */ +def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */ +def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ +def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */ +def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */ +def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */ +def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ + +def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */ + +DEF( push_minus1, 1, 0, 1, none_int) +DEF( push_0, 1, 0, 1, none_int) +DEF( push_1, 1, 0, 1, none_int) +DEF( push_2, 1, 0, 1, none_int) +DEF( push_3, 1, 0, 1, none_int) +DEF( push_4, 1, 0, 1, none_int) +DEF( push_5, 1, 0, 1, none_int) +DEF( push_6, 1, 0, 1, none_int) +DEF( push_7, 1, 0, 1, none_int) +DEF( push_i8, 2, 0, 1, i8) +DEF( push_i16, 3, 0, 1, i16) +DEF( push_const8, 2, 0, 1, const8) +DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */ +DEF(push_empty_string, 1, 0, 1, none) + +DEF( get_loc8, 2, 0, 1, loc8) +DEF( put_loc8, 2, 1, 0, loc8) +DEF( set_loc8, 2, 1, 1, loc8) + +DEF( get_loc0_loc1, 1, 0, 2, none_loc) +DEF( get_loc0, 1, 0, 1, none_loc) +DEF( get_loc1, 1, 0, 1, none_loc) +DEF( get_loc2, 1, 0, 1, none_loc) +DEF( get_loc3, 1, 0, 1, none_loc) +DEF( put_loc0, 1, 1, 0, none_loc) +DEF( put_loc1, 1, 1, 0, none_loc) +DEF( put_loc2, 1, 1, 0, none_loc) +DEF( put_loc3, 1, 1, 0, none_loc) +DEF( set_loc0, 1, 1, 1, none_loc) +DEF( set_loc1, 1, 1, 1, none_loc) +DEF( set_loc2, 1, 1, 1, none_loc) +DEF( set_loc3, 1, 1, 1, none_loc) +DEF( get_arg0, 1, 0, 1, none_arg) +DEF( get_arg1, 1, 0, 1, none_arg) +DEF( get_arg2, 1, 0, 1, none_arg) +DEF( get_arg3, 1, 0, 1, none_arg) +DEF( put_arg0, 1, 1, 0, none_arg) +DEF( put_arg1, 1, 1, 0, none_arg) +DEF( put_arg2, 1, 1, 0, none_arg) +DEF( put_arg3, 1, 1, 0, none_arg) +DEF( set_arg0, 1, 1, 1, none_arg) +DEF( set_arg1, 1, 1, 1, none_arg) +DEF( set_arg2, 1, 1, 1, none_arg) +DEF( set_arg3, 1, 1, 1, none_arg) +DEF( get_var_ref0, 1, 0, 1, none_var_ref) +DEF( get_var_ref1, 1, 0, 1, none_var_ref) +DEF( get_var_ref2, 1, 0, 1, none_var_ref) +DEF( get_var_ref3, 1, 0, 1, none_var_ref) +DEF( put_var_ref0, 1, 1, 0, none_var_ref) +DEF( put_var_ref1, 1, 1, 0, none_var_ref) +DEF( put_var_ref2, 1, 1, 0, none_var_ref) +DEF( put_var_ref3, 1, 1, 0, none_var_ref) +DEF( set_var_ref0, 1, 1, 1, none_var_ref) +DEF( set_var_ref1, 1, 1, 1, none_var_ref) +DEF( set_var_ref2, 1, 1, 1, none_var_ref) +DEF( set_var_ref3, 1, 1, 1, none_var_ref) + +DEF( get_length, 1, 1, 1, none) + +DEF( if_false8, 2, 1, 0, label8) +DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */ +DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */ +DEF( goto16, 3, 0, 0, label16) + +DEF( call0, 1, 1, 1, npopx) +DEF( call1, 1, 1, 1, npopx) +DEF( call2, 1, 1, 1, npopx) +DEF( call3, 1, 1, 1, npopx) + +DEF( is_undefined, 1, 1, 1, none) +DEF( is_null, 1, 1, 1, none) +DEF(typeof_is_undefined, 1, 1, 1, none) +DEF( typeof_is_function, 1, 1, 1, none) + +#undef DEF +#undef def +#endif /* DEF */ diff --git a/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs.c b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs.c new file mode 100644 index 0000000..78da36d --- /dev/null +++ b/host/cred-script/vendor/rquickjs-sys/quickjs/quickjs.c @@ -0,0 +1,58389 @@ +/* + * QuickJS Javascript Engine + * + * Copyright (c) 2017-2025 Fabrice Bellard + * Copyright (c) 2017-2025 Charlie Gordon + * Copyright (c) 2023-2025 Ben Noordhuis + * Copyright (c) 2023-2025 Saúl Ibarra Corretgé + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#if !defined(_MSC_VER) +#include +#if defined(_WIN32) +#include +#endif +#endif +#if defined(_WIN32) +#include +#endif +#include +#include +#include + +#include "cutils.h" +#include "list.h" +#include "quickjs.h" +#include "libregexp.h" +#include "dtoa.h" + +#if defined(EMSCRIPTEN) || defined(_MSC_VER) +#define DIRECT_DISPATCH 0 +#else +#define DIRECT_DISPATCH 1 +#endif + +#if defined(__APPLE__) +#define MALLOC_OVERHEAD 0 +#else +#define MALLOC_OVERHEAD 8 +#endif + +#if defined(__NEWLIB__) +#define NO_TM_GMTOFF +#endif + +// atomic_store etc. are completely busted in recent versions of tcc; +// somehow the compiler forgets to load |ptr| into %rdi when calling +// the __atomic_*() helpers in its lib/stdatomic.c and lib/atomic.S +#if !defined(__TINYC__) && !defined(EMSCRIPTEN) && !defined(__wasi__) && !__STDC_NO_ATOMICS__ +#include "quickjs-c-atomics.h" +#define CONFIG_ATOMICS +#endif + +#ifndef __GNUC__ +#define __extension__ +#endif + +#ifndef NDEBUG +#define ENABLE_DUMPS +#endif + +//#define FORCE_GC_AT_MALLOC /* test the GC by forcing it before each object allocation */ + +#define check_dump_flag(rt, flag) ((rt->dump_flags & (flag +0)) == (flag +0)) + +#define STRINGIFY_(x) #x +#define STRINGIFY(x) STRINGIFY_(x) + +#define QJS_VERSION_STRING \ + STRINGIFY(QJS_VERSION_MAJOR) "." STRINGIFY(QJS_VERSION_MINOR) "." STRINGIFY(QJS_VERSION_PATCH) QJS_VERSION_SUFFIX + +const char* JS_GetVersion(void) { + return QJS_VERSION_STRING; +} + +#undef STRINFIGY_ +#undef STRINGIFY + +static inline JSValueConst *vc(JSValue *vals) +{ + return (JSValueConst *)vals; +} + +static inline JSValue unsafe_unconst(JSValueConst v) +{ +#ifdef JS_CHECK_JSVALUE + return (JSValue)v; +#else + return v; +#endif +} + +static inline JSValueConst safe_const(JSValue v) +{ +#ifdef JS_CHECK_JSVALUE + return (JSValueConst)v; +#else + return v; +#endif +} + +enum { + /* classid tag */ /* union usage | properties */ + JS_CLASS_OBJECT = 1, /* must be first */ + JS_CLASS_ARRAY, /* u.array | length */ + JS_CLASS_ERROR, + JS_CLASS_NUMBER, /* u.object_data */ + JS_CLASS_STRING, /* u.object_data */ + JS_CLASS_BOOLEAN, /* u.object_data */ + JS_CLASS_SYMBOL, /* u.object_data */ + JS_CLASS_ARGUMENTS, /* u.array | length */ + JS_CLASS_MAPPED_ARGUMENTS, /* | length */ + JS_CLASS_DATE, /* u.object_data */ + JS_CLASS_MODULE_NS, + JS_CLASS_C_FUNCTION, /* u.cfunc */ + JS_CLASS_BYTECODE_FUNCTION, /* u.func */ + JS_CLASS_BOUND_FUNCTION, /* u.bound_function */ + JS_CLASS_C_FUNCTION_DATA, /* u.c_function_data_record */ + JS_CLASS_C_CLOSURE, /* u.c_closure_record */ + JS_CLASS_GENERATOR_FUNCTION, /* u.func */ + JS_CLASS_FOR_IN_ITERATOR, /* u.for_in_iterator */ + JS_CLASS_REGEXP, /* u.regexp */ + JS_CLASS_ARRAY_BUFFER, /* u.array_buffer */ + JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */ + JS_CLASS_UINT8C_ARRAY, /* u.array (typed_array) */ + JS_CLASS_INT8_ARRAY, /* u.array (typed_array) */ + JS_CLASS_UINT8_ARRAY, /* u.array (typed_array) */ + JS_CLASS_INT16_ARRAY, /* u.array (typed_array) */ + JS_CLASS_UINT16_ARRAY, /* u.array (typed_array) */ + JS_CLASS_INT32_ARRAY, /* u.array (typed_array) */ + JS_CLASS_UINT32_ARRAY, /* u.array (typed_array) */ + JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */ + JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */ + JS_CLASS_FLOAT16_ARRAY, /* u.array (typed_array) */ + JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */ + JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */ + JS_CLASS_DATAVIEW, /* u.typed_array */ + JS_CLASS_BIG_INT, /* u.object_data */ + JS_CLASS_MAP, /* u.map_state */ + JS_CLASS_SET, /* u.map_state */ + JS_CLASS_WEAKMAP, /* u.map_state */ + JS_CLASS_WEAKSET, /* u.map_state */ + JS_CLASS_ITERATOR, + JS_CLASS_ITERATOR_CONCAT, /* u.iterator_concat_data */ + JS_CLASS_ITERATOR_HELPER, /* u.iterator_helper_data */ + JS_CLASS_ITERATOR_WRAP, /* u.iterator_wrap_data */ + JS_CLASS_MAP_ITERATOR, /* u.map_iterator_data */ + JS_CLASS_SET_ITERATOR, /* u.map_iterator_data */ + JS_CLASS_ARRAY_ITERATOR, /* u.array_iterator_data */ + JS_CLASS_STRING_ITERATOR, /* u.array_iterator_data */ + JS_CLASS_REGEXP_STRING_ITERATOR, /* u.regexp_string_iterator_data */ + JS_CLASS_GENERATOR, /* u.generator_data */ + JS_CLASS_PROXY, /* u.proxy_data */ + JS_CLASS_PROMISE, /* u.promise_data */ + JS_CLASS_PROMISE_RESOLVE_FUNCTION, /* u.promise_function_data */ + JS_CLASS_PROMISE_REJECT_FUNCTION, /* u.promise_function_data */ + JS_CLASS_ASYNC_FUNCTION, /* u.func */ + JS_CLASS_ASYNC_FUNCTION_RESOLVE, /* u.async_function_data */ + JS_CLASS_ASYNC_FUNCTION_REJECT, /* u.async_function_data */ + JS_CLASS_ASYNC_FROM_SYNC_ITERATOR, /* u.async_from_sync_iterator_data */ + JS_CLASS_ASYNC_GENERATOR_FUNCTION, /* u.func */ + JS_CLASS_ASYNC_GENERATOR, /* u.async_generator_data */ + JS_CLASS_WEAK_REF, + JS_CLASS_FINALIZATION_REGISTRY, + JS_CLASS_DOM_EXCEPTION, + JS_CLASS_CALL_SITE, + + JS_CLASS_INIT_COUNT, /* last entry for predefined classes */ +}; + +/* number of typed array types */ +#define JS_TYPED_ARRAY_COUNT (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1) +static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT]; +#define typed_array_size_log2(classid) (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY]) + +typedef enum JSErrorEnum { + JS_EVAL_ERROR, + JS_RANGE_ERROR, + JS_REFERENCE_ERROR, + JS_SYNTAX_ERROR, + JS_TYPE_ERROR, + JS_URI_ERROR, + JS_INTERNAL_ERROR, + JS_AGGREGATE_ERROR, + + JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */ + JS_PLAIN_ERROR = JS_NATIVE_ERROR_COUNT +} JSErrorEnum; + +#define JS_MAX_LOCAL_VARS 65535 +#define JS_STACK_SIZE_MAX 65534 +#define JS_STRING_LEN_MAX ((1 << 30) - 1) +// 1,024 bytes is about the cutoff point where it starts getting +// more profitable to ref slice than to copy +#define JS_STRING_SLICE_LEN_MAX 1024 // in bytes + +#define __exception __attribute__((warn_unused_result)) + +typedef struct JSShape JSShape; +typedef struct JSString JSString; +typedef struct JSString JSAtomStruct; + +#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v)) + +typedef enum { + JS_GC_PHASE_NONE, + JS_GC_PHASE_DECREF, + JS_GC_PHASE_REMOVE_CYCLES, +} JSGCPhaseEnum; + +typedef struct JSMallocState { + size_t malloc_count; + size_t malloc_size; + size_t malloc_limit; + void *opaque; /* user opaque */ +} JSMallocState; + +typedef struct JSRuntimeFinalizerState { + struct JSRuntimeFinalizerState *next; + JSRuntimeFinalizer *finalizer; + void *arg; +} JSRuntimeFinalizerState; + +typedef struct JSValueLink { + struct JSValueLink *next; + JSValueConst value; +} JSValueLink; + +struct JSRuntime { + JSMallocFunctions mf; + JSMallocState malloc_state; + const char *rt_info; + + int atom_hash_size; /* power of two */ + int atom_count; + int atom_size; + int atom_count_resize; /* resize hash table at this count */ + uint32_t *atom_hash; + JSAtomStruct **atom_array; + int atom_free_index; /* 0 = none */ + + JSClassID js_class_id_alloc; /* counter for user defined classes */ + int class_count; /* size of class_array */ + JSClass *class_array; + + struct list_head context_list; /* list of JSContext.link */ + /* list of JSGCObjectHeader.link. List of allocated GC objects (used + by the garbage collector) */ + struct list_head gc_obj_list; + /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */ + struct list_head gc_zero_ref_count_list; + struct list_head tmp_obj_list; /* used during GC */ + JSGCPhaseEnum gc_phase : 8; + size_t malloc_gc_threshold; +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + struct list_head string_list; /* list of JSString.link */ +#endif + /* stack limitation */ + uintptr_t stack_size; /* in bytes, 0 if no limit */ + uintptr_t stack_top; + uintptr_t stack_limit; /* lower stack limit */ + + JSValue current_exception; + /* true if inside an out of memory error, to avoid recursing */ + bool in_out_of_memory; + bool sausage_had_out_of_memory; + /* true if inside build_backtrace, to avoid recursing */ + bool in_build_stack_trace; + /* true if inside JS_FreeRuntime */ + bool in_free; + + struct JSStackFrame *current_stack_frame; + + JSInterruptHandler *interrupt_handler; + void *interrupt_opaque; + + JSPromiseHook *promise_hook; + void *promise_hook_opaque; + // for smuggling the parent promise from js_promise_then + // to js_promise_constructor + JSValueLink *parent_promise; + + JSHostPromiseRejectionTracker *host_promise_rejection_tracker; + void *host_promise_rejection_tracker_opaque; + + struct list_head job_list; /* list of JSJobEntry.link */ + + JSModuleNormalizeFunc *module_normalize_func; + JSModuleLoaderFunc *module_loader_func; + void *module_loader_opaque; + /* timestamp for internal use in module evaluation */ + int64_t module_async_evaluation_next_timestamp; + + /* used to allocate, free and clone SharedArrayBuffers */ + JSSharedArrayBufferFunctions sab_funcs; + + bool can_block; /* true if Atomics.wait can block */ + uint32_t dump_flags : 24; + + /* Shape hash table */ + int shape_hash_bits; + int shape_hash_size; + int shape_hash_count; /* number of hashed shapes */ + JSShape **shape_hash; + void *user_opaque; + void *libc_opaque; + JSRuntimeFinalizerState *finalizers; +}; + +struct JSClass { + uint32_t class_id; /* 0 means free entry */ + JSAtom class_name; + JSClassFinalizer *finalizer; + JSClassGCMark *gc_mark; + JSClassCall *call; + /* pointers for exotic behavior, can be NULL if none are present */ + const JSClassExoticMethods *exotic; +}; + +typedef struct JSStackFrame { + struct JSStackFrame *prev_frame; /* NULL if first stack frame */ + JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */ + JSValue *arg_buf; /* arguments */ + JSValue *var_buf; /* variables */ + struct list_head var_ref_list; /* list of JSVarRef.link */ + uint8_t *cur_pc; /* only used in bytecode functions : PC of the + instruction after the call */ + uint32_t arg_count : 31; + uint32_t is_strict_mode : 1; + /* only used in generators. Current stack pointer value. NULL if + the function is running. */ + JSValue *cur_sp; +} JSStackFrame; + +typedef enum { + JS_GC_OBJ_TYPE_JS_OBJECT, + JS_GC_OBJ_TYPE_FUNCTION_BYTECODE, + JS_GC_OBJ_TYPE_SHAPE, + JS_GC_OBJ_TYPE_VAR_REF, + JS_GC_OBJ_TYPE_ASYNC_FUNCTION, + JS_GC_OBJ_TYPE_JS_CONTEXT, +} JSGCObjectTypeEnum; + +/* header for GC objects. GC objects are C data structures with a + reference count that can reference other GC objects. JS Objects are + a particular type of GC object. */ +struct JSGCObjectHeader { + int ref_count; /* must come first, 32-bit */ + JSGCObjectTypeEnum gc_obj_type : 4; + uint8_t mark : 4; /* used by the GC */ + uint8_t dummy1; /* not used by the GC */ + uint16_t dummy2; /* not used by the GC */ + struct list_head link; +}; + +typedef struct JSVarRef { + union { + JSGCObjectHeader header; /* must come first */ + struct { + int __gc_ref_count; /* corresponds to header.ref_count */ + uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ + uint8_t is_detached; + }; + }; + JSValue *pvalue; /* pointer to the value, either on the stack or + to 'value' */ + JSValue value; /* used when the variable is no longer on the stack */ +} JSVarRef; + +typedef struct JSRefCountHeader { + int ref_count; +} JSRefCountHeader; + +/* bigint */ +typedef int32_t js_slimb_t; +typedef uint32_t js_limb_t; +typedef int64_t js_sdlimb_t; +typedef uint64_t js_dlimb_t; + +#define JS_LIMB_DIGITS 9 + +/* Must match the size of short_big_int in JSValueUnion */ +#define JS_LIMB_BITS 32 +#define JS_SHORT_BIG_INT_BITS JS_LIMB_BITS +#define JS_BIGINT_MAX_SIZE ((1024 * 1024) / JS_LIMB_BITS) /* in limbs */ +#define JS_SHORT_BIG_INT_MIN INT32_MIN +#define JS_SHORT_BIG_INT_MAX INT32_MAX + + +typedef struct JSBigInt { + JSRefCountHeader header; /* must come first, 32-bit */ + uint32_t len; /* number of limbs, >= 1 */ + js_limb_t tab[]; /* two's complement representation, always + normalized so that 'len' is the minimum + possible length >= 1 */ +} JSBigInt; + +/* this bigint structure can hold a 64 bit integer */ +typedef struct { + js_limb_t big_int_buf[sizeof(JSBigInt) / sizeof(js_limb_t)]; /* for JSBigInt */ + /* must come just after */ + js_limb_t tab[(64 + JS_LIMB_BITS - 1) / JS_LIMB_BITS]; +} JSBigIntBuf; + +typedef enum { + JS_AUTOINIT_ID_PROTOTYPE, + JS_AUTOINIT_ID_MODULE_NS, + JS_AUTOINIT_ID_PROP, + JS_AUTOINIT_ID_BYTECODE, +} JSAutoInitIDEnum; + +enum { + JS_BUILTIN_ARRAY_FROMASYNC = 1, +}; + +/* must be large enough to have a negligible runtime cost and small + enough to call the interrupt callback often. */ +#define JS_INTERRUPT_COUNTER_INIT 10000 + +struct JSContext { + JSGCObjectHeader header; /* must come first */ + JSRuntime *rt; + struct list_head link; + + uint16_t binary_object_count; + int binary_object_size; + + JSShape *array_shape; /* initial shape for Array objects */ + + JSValue *class_proto; + JSValue function_proto; + JSValue function_ctor; + JSValue array_ctor; + JSValue regexp_ctor; + JSValue promise_ctor; + JSValue native_error_proto[JS_NATIVE_ERROR_COUNT]; + JSValue error_ctor; + JSValue error_back_trace; + JSValue error_prepare_stack; + JSValue error_stack_trace_limit; + JSValue iterator_ctor; + JSValue iterator_ctor_getset; + JSValue iterator_proto; + JSValue async_iterator_proto; + JSValue array_proto_values; + JSValue throw_type_error; + JSValue eval_obj; + + JSValue global_obj; /* global object */ + JSValue global_var_obj; /* contains the global let/const definitions */ + + double time_origin; + + uint64_t random_state; + + /* when the counter reaches zero, JSRutime.interrupt_handler is called */ + int interrupt_counter; + + struct list_head loaded_modules; /* list of JSModuleDef.link */ + + /* if NULL, RegExp compilation is not supported */ + JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern, + JSValueConst flags); + /* if NULL, eval is not supported */ + JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj, + const char *input, size_t input_len, + const char *filename, int line, int flags, int scope_idx); + void *user_opaque; +}; + +typedef union JSFloat64Union { + double d; + uint64_t u64; + uint32_t u32[2]; +} JSFloat64Union; + +typedef enum { + JS_WEAK_REF_KIND_MAP, + JS_WEAK_REF_KIND_WEAK_REF, + JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY, +} JSWeakRefKindEnum; + +typedef struct JSWeakRefRecord { + JSWeakRefKindEnum kind; + struct JSWeakRefRecord *next_weak_ref; + union { + struct JSMapRecord *map_record; + struct JSWeakRefData *weak_ref_data; + struct JSFinRecEntry *fin_rec_entry; + } u; +} JSWeakRefRecord; + +typedef struct JSMapRecord { + int ref_count; /* used during enumeration to avoid freeing the record */ + bool empty; /* true if the record is deleted */ + struct JSMapState *map; + struct list_head link; + struct list_head hash_link; + JSValue key; + JSValue value; +} JSMapRecord; + +typedef struct JSMapState { + bool is_weak; /* true if WeakSet/WeakMap */ + struct list_head records; /* list of JSMapRecord.link */ + uint32_t record_count; + struct list_head *hash_table; + uint32_t hash_size; /* must be a power of two */ + uint32_t record_count_threshold; /* count at which a hash table + resize is needed */ +} JSMapState; + +enum +{ + JS_TO_STRING_IS_PROPERTY_KEY = 1 << 0, + JS_TO_STRING_NO_SIDE_EFFECTS = 1 << 1, +}; + +enum { + JS_ATOM_TYPE_STRING = 1, + JS_ATOM_TYPE_GLOBAL_SYMBOL, + JS_ATOM_TYPE_SYMBOL, + JS_ATOM_TYPE_PRIVATE, +}; + +enum { + JS_ATOM_HASH_SYMBOL, + JS_ATOM_HASH_PRIVATE, +}; + +typedef enum { + JS_ATOM_KIND_STRING, + JS_ATOM_KIND_SYMBOL, + JS_ATOM_KIND_PRIVATE, +} JSAtomKindEnum; + +typedef enum { + JS_STRING_KIND_NORMAL, + JS_STRING_KIND_SLICE, +} JSStringKind; + +#define JS_ATOM_HASH_MASK ((1 << 29) - 1) + +struct JSString { + JSRefCountHeader header; /* must come first, 32-bit */ + uint32_t len : 31; + uint32_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */ + /* for JS_ATOM_TYPE_SYMBOL: hash = 0, atom_type = 3, + for JS_ATOM_TYPE_PRIVATE: hash = 1, atom_type = 3 + XXX: could change encoding to have one more bit in hash */ + uint32_t hash : 29; + uint32_t kind : 1; + uint32_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */ + uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */ + JSWeakRefRecord *first_weak_ref; +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + struct list_head link; /* string list */ +#endif +}; + +typedef struct JSStringSlice { + JSString *parent; + uint32_t start; // in bytes, not characters +} JSStringSlice; + +static inline void *strv(JSString *p) +{ + JSStringSlice *slice; + + switch (p->kind) { + case JS_STRING_KIND_NORMAL: + return (void *)&p[1]; + case JS_STRING_KIND_SLICE: + slice = (void *)&p[1]; + return (char *)&slice->parent[1] + slice->start; + } + abort(); + return NULL; +} + +static inline uint8_t *str8(JSString *p) +{ + return strv(p); +} + +static inline uint16_t *str16(JSString *p) +{ + return strv(p); +} + +typedef struct JSClosureVar { + uint8_t is_local : 1; + uint8_t is_arg : 1; + uint8_t is_const : 1; + uint8_t is_lexical : 1; + uint8_t var_kind : 4; /* see JSVarKindEnum */ + /* 8 bits available */ + uint16_t var_idx; /* is_local = true: index to a normal variable of the + parent function. otherwise: index to a closure + variable of the parent function */ + JSAtom var_name; +} JSClosureVar; + +#define ARG_SCOPE_INDEX 1 +#define ARG_SCOPE_END (-2) + +typedef struct JSVarScope { + int parent; /* index into fd->scopes of the enclosing scope */ + int first; /* index into fd->vars of the last variable in this scope */ +} JSVarScope; + +typedef enum { + /* XXX: add more variable kinds here instead of using bit fields */ + JS_VAR_NORMAL, + JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */ + JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator + function declaration */ + JS_VAR_CATCH, + JS_VAR_FUNCTION_NAME, /* function expression name */ + JS_VAR_PRIVATE_FIELD, + JS_VAR_PRIVATE_METHOD, + JS_VAR_PRIVATE_GETTER, + JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */ + JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */ +} JSVarKindEnum; + +/* XXX: could use a different structure in bytecode functions to save + memory */ +typedef struct JSVarDef { + JSAtom var_name; + /* index into fd->scopes of this variable lexical scope */ + int scope_level; + /* during compilation: + - if scope_level = 0: scope in which the variable is defined + - if scope_level != 0: index into fd->vars of the next + variable in the same or enclosing lexical scope + in a bytecode function: + index into fd->vars of the next + variable in the same or enclosing lexical scope + */ + int scope_next; + uint8_t is_const : 1; + uint8_t is_lexical : 1; + uint8_t is_captured : 1; + uint8_t is_static_private : 1; /* only used during private class field parsing */ + uint8_t var_kind : 4; /* see JSVarKindEnum */ + /* only used during compilation: function pool index for lexical + variables with var_kind = + JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of + the definition of the 'var' variables (they have scope_level = + 0) */ + int func_pool_idx : 24; /* only used during compilation : index in + the constant pool for hoisted function + definition */ +} JSVarDef; + +/* for the encoding of the pc2line table */ +#define PC2LINE_BASE (-1) +#define PC2LINE_RANGE 5 +#define PC2LINE_OP_FIRST 1 +#define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE) + +typedef enum JSFunctionKindEnum { + JS_FUNC_NORMAL = 0, + JS_FUNC_GENERATOR = (1 << 0), + JS_FUNC_ASYNC = (1 << 1), + JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC), +} JSFunctionKindEnum; + +typedef struct JSFunctionBytecode { + JSGCObjectHeader header; /* must come first */ + uint8_t is_strict_mode : 1; + uint8_t has_prototype : 1; /* true if a prototype field is necessary */ + uint8_t has_simple_parameter_list : 1; + uint8_t is_derived_class_constructor : 1; + /* true if home_object needs to be initialized */ + uint8_t need_home_object : 1; + uint8_t func_kind : 2; + uint8_t new_target_allowed : 1; + uint8_t super_call_allowed : 1; + uint8_t super_allowed : 1; + uint8_t arguments_allowed : 1; + uint8_t backtrace_barrier : 1; /* stop backtrace on this function */ + /* XXX: 5 bits available */ + uint8_t *byte_code_buf; /* (self pointer) */ + int byte_code_len; + JSAtom func_name; + JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */ + JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */ + uint16_t arg_count; + uint16_t var_count; + uint16_t defined_arg_count; /* for length function property */ + uint16_t stack_size; /* maximum stack size */ + JSContext *realm; /* function realm */ + JSValue *cpool; /* constant pool (self pointer) */ + int cpool_count; + int closure_var_count; + JSAtom filename; + int line_num; + int col_num; + int source_len; + int pc2line_len; + uint8_t *pc2line_buf; + char *source; +} JSFunctionBytecode; + +typedef struct JSBoundFunction { + JSValue func_obj; + JSValue this_val; + int argc; + JSValue argv[]; +} JSBoundFunction; + +typedef enum JSIteratorKindEnum { + JS_ITERATOR_KIND_KEY, + JS_ITERATOR_KIND_VALUE, + JS_ITERATOR_KIND_KEY_AND_VALUE, +} JSIteratorKindEnum; + +typedef enum JSIteratorHelperKindEnum { + JS_ITERATOR_HELPER_KIND_DROP, + JS_ITERATOR_HELPER_KIND_EVERY, + JS_ITERATOR_HELPER_KIND_FILTER, + JS_ITERATOR_HELPER_KIND_FIND, + JS_ITERATOR_HELPER_KIND_FLAT_MAP, + JS_ITERATOR_HELPER_KIND_FOR_EACH, + JS_ITERATOR_HELPER_KIND_MAP, + JS_ITERATOR_HELPER_KIND_SOME, + JS_ITERATOR_HELPER_KIND_TAKE, +} JSIteratorHelperKindEnum; + +typedef struct JSForInIterator { + JSValue obj; + bool is_array; + uint32_t array_length; + uint32_t idx; +} JSForInIterator; + +typedef struct JSRegExp { + JSString *pattern; + JSString *bytecode; /* also contains the flags */ +} JSRegExp; + +typedef struct JSProxyData { + JSValue target; + JSValue handler; + uint8_t is_func; + uint8_t is_revoked; +} JSProxyData; + +typedef struct JSArrayBuffer { + int byte_length; /* 0 if detached */ + int max_byte_length; /* -1 if not resizable; >= byte_length otherwise */ + uint8_t detached; + uint8_t shared; /* if shared, the array buffer cannot be detached */ + uint8_t *data; /* NULL if detached */ + struct list_head array_list; + void *opaque; + JSFreeArrayBufferDataFunc *free_func; +} JSArrayBuffer; + +typedef struct JSTypedArray { + struct list_head link; /* link to arraybuffer */ + JSObject *obj; /* back pointer to the TypedArray/DataView object */ + JSObject *buffer; /* based array buffer */ + uint32_t offset; /* byte offset in the array buffer */ + uint32_t length; /* byte length in the array buffer */ + bool track_rab; /* auto-track length of backing array buffer */ +} JSTypedArray; + +typedef struct JSAsyncFunctionState { + JSValue this_val; /* 'this' generator argument */ + int argc; /* number of function arguments */ + bool throw_flag; /* used to throw an exception in JS_CallInternal() */ + JSStackFrame frame; +} JSAsyncFunctionState; + +/* XXX: could use an object instead to avoid the + JS_TAG_ASYNC_FUNCTION tag for the GC */ +typedef struct JSAsyncFunctionData { + JSGCObjectHeader header; /* must come first */ + JSValue resolving_funcs[2]; + bool is_active; /* true if the async function state is valid */ + JSAsyncFunctionState func_state; +} JSAsyncFunctionData; + +typedef struct JSReqModuleEntry { + JSAtom module_name; + JSModuleDef *module; /* used using resolution */ +} JSReqModuleEntry; + +typedef enum JSExportTypeEnum { + JS_EXPORT_TYPE_LOCAL, + JS_EXPORT_TYPE_INDIRECT, +} JSExportTypeEnum; + +typedef struct JSExportEntry { + union { + struct { + int var_idx; /* closure variable index */ + JSVarRef *var_ref; /* if != NULL, reference to the variable */ + } local; /* for local export */ + int req_module_idx; /* module for indirect export */ + } u; + JSExportTypeEnum export_type; + JSAtom local_name; /* '*' if export ns from. not used for local + export after compilation */ + JSAtom export_name; /* exported variable name */ +} JSExportEntry; + +typedef struct JSStarExportEntry { + int req_module_idx; /* in req_module_entries */ +} JSStarExportEntry; + +typedef struct JSImportEntry { + int var_idx; /* closure variable index */ + JSAtom import_name; + int req_module_idx; /* in req_module_entries */ +} JSImportEntry; + +typedef enum { + JS_MODULE_STATUS_UNLINKED, + JS_MODULE_STATUS_LINKING, + JS_MODULE_STATUS_LINKED, + JS_MODULE_STATUS_EVALUATING, + JS_MODULE_STATUS_EVALUATING_ASYNC, + JS_MODULE_STATUS_EVALUATED, +} JSModuleStatus; + +struct JSModuleDef { + JSRefCountHeader header; /* must come first, 32-bit */ + JSAtom module_name; + struct list_head link; + + JSReqModuleEntry *req_module_entries; + int req_module_entries_count; + int req_module_entries_size; + + JSExportEntry *export_entries; + int export_entries_count; + int export_entries_size; + + JSStarExportEntry *star_export_entries; + int star_export_entries_count; + int star_export_entries_size; + + JSImportEntry *import_entries; + int import_entries_count; + int import_entries_size; + + JSValue module_ns; + JSValue func_obj; /* only used for JS modules */ + JSModuleInitFunc *init_func; /* only used for C modules */ + bool has_tla; /* true if func_obj contains await */ + bool resolved; + bool func_created; + JSModuleStatus status : 8; + /* temp use during js_module_link() & js_module_evaluate() */ + int dfs_index, dfs_ancestor_index; + JSModuleDef *stack_prev; + /* temp use during js_module_evaluate() */ + JSModuleDef **async_parent_modules; + int async_parent_modules_count; + int async_parent_modules_size; + int pending_async_dependencies; + bool async_evaluation; + int64_t async_evaluation_timestamp; + JSModuleDef *cycle_root; + JSValue promise; /* corresponds to spec field: capability */ + JSValue resolving_funcs[2]; /* corresponds to spec field: capability */ + /* true if evaluation yielded an exception. It is saved in + eval_exception */ + bool eval_has_exception; + JSValue eval_exception; + JSValue meta_obj; /* for import.meta */ +}; + +typedef struct JSJobEntry { + struct list_head link; + JSContext *ctx; + JSJobFunc *job_func; + int argc; + JSValue argv[]; +} JSJobEntry; + +typedef struct JSProperty { + union { + JSValue value; /* JS_PROP_NORMAL */ + struct { /* JS_PROP_GETSET */ + JSObject *getter; /* NULL if undefined */ + JSObject *setter; /* NULL if undefined */ + } getset; + JSVarRef *var_ref; /* JS_PROP_VARREF */ + struct { /* JS_PROP_AUTOINIT */ + /* in order to use only 2 pointers, we compress the realm + and the init function pointer */ + uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x) + in the 2 low bits */ + void *opaque; + } init; + } u; +} JSProperty; + +#define JS_PROP_INITIAL_SIZE 2 +#define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */ +#define JS_ARRAY_INITIAL_SIZE 2 + +typedef struct JSShapeProperty { + uint32_t hash_next : 26; /* 0 if last in list */ + uint32_t flags : 6; /* JS_PROP_XXX */ + JSAtom atom; /* JS_ATOM_NULL = free property entry */ +} JSShapeProperty; + +struct JSShape { + /* hash table of size hash_mask + 1 before the start of the + structure (see prop_hash_end()). */ + JSGCObjectHeader header; + /* true if the shape is inserted in the shape hash table. If not, + JSShape.hash is not valid */ + uint8_t is_hashed; + /* If true, the shape may have small array index properties 'n' with 0 + <= n <= 2^31-1. If false, the shape is guaranteed not to have + small array index properties */ + uint8_t has_small_array_index; + uint32_t hash; /* current hash value */ + uint32_t prop_hash_mask; + int prop_size; /* allocated properties */ + int prop_count; /* include deleted properties */ + int deleted_prop_count; + JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */ + JSObject *proto; + JSShapeProperty prop[]; /* prop_size elements */ +}; + +struct JSObject { + union { + JSGCObjectHeader header; + struct { + int __gc_ref_count; /* corresponds to header.ref_count */ + uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ + + uint8_t extensible : 1; + uint8_t free_mark : 1; /* only used when freeing objects with cycles */ + uint8_t is_exotic : 1; /* true if object has exotic property handlers */ + uint8_t fast_array : 1; /* true if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */ + uint8_t is_constructor : 1; /* true if object is a constructor function */ + uint8_t is_uncatchable_error : 1; /* if true, error is not catchable */ + uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */ + uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */ + uint16_t class_id; /* see JS_CLASS_x */ + }; + }; + /* byte offsets: 16/24 */ + JSShape *shape; /* prototype and property names + flag */ + JSProperty *prop; /* array of properties */ + /* byte offsets: 24/40 */ + JSWeakRefRecord *first_weak_ref; + /* byte offsets: 28/48 */ + union { + void *opaque; + struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */ + struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */ + struct JSCClosureRecord *c_closure_record; /* JS_CLASS_C_CLOSURE */ + struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */ + struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */ + struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */ + struct JSMapState *map_state; /* JS_CLASS_MAP..JS_CLASS_WEAKSET */ + struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */ + struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */ + struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */ + struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */ + struct JSIteratorConcatData *iterator_concat_data; /* JS_CLASS_ITERATOR_CONCAT */ + struct JSIteratorHelperData *iterator_helper_data; /* JS_CLASS_ITERATOR_HELPER */ + struct JSIteratorWrapData *iterator_wrap_data; /* JS_CLASS_ITERATOR_WRAP */ + struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */ + struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */ + struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */ + struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */ + struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */ + struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */ + struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */ + /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */ + struct JSFunctionBytecode *function_bytecode; + JSVarRef **var_refs; + JSObject *home_object; /* for 'super' access */ + } func; + struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */ + JSContext *realm; + JSCFunctionType c_function; + uint8_t length; + uint8_t cproto; + int16_t magic; + } cfunc; + /* array part for fast arrays and typed arrays */ + struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ + union { + uint32_t size; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ + struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ + } u1; + union { + JSValue *values; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ + void *ptr; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ + int8_t *int8_ptr; /* JS_CLASS_INT8_ARRAY */ + uint8_t *uint8_ptr; /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */ + int16_t *int16_ptr; /* JS_CLASS_INT16_ARRAY */ + uint16_t *uint16_ptr; /* JS_CLASS_UINT16_ARRAY */ + int32_t *int32_ptr; /* JS_CLASS_INT32_ARRAY */ + uint32_t *uint32_ptr; /* JS_CLASS_UINT32_ARRAY */ + int64_t *int64_ptr; /* JS_CLASS_INT64_ARRAY */ + uint64_t *uint64_ptr; /* JS_CLASS_UINT64_ARRAY */ + uint16_t *fp16_ptr; /* JS_CLASS_FLOAT16_ARRAY */ + float *float_ptr; /* JS_CLASS_FLOAT32_ARRAY */ + double *double_ptr; /* JS_CLASS_FLOAT64_ARRAY */ + } u; + uint32_t count; /* <= 2^31-1. 0 for a detached typed array */ + } array; /* 12/20 bytes */ + JSRegExp regexp; /* JS_CLASS_REGEXP: 8/16 bytes */ + JSValue object_data; /* for JS_SetObjectData(): 8/16/16 bytes */ + } u; + /* byte sizes: 40/48/72 */ +}; + +typedef struct JSCallSiteData { + JSValue filename; + JSValue func; + JSValue func_name; + bool native; + int line_num; + int col_num; +} JSCallSiteData; + +enum { + __JS_ATOM_NULL = JS_ATOM_NULL, +#define DEF(name, str) JS_ATOM_ ## name, +#include "quickjs-atom.h" +#undef DEF + JS_ATOM_END, +}; +#define JS_ATOM_LAST_KEYWORD JS_ATOM_super +#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield + +static const char js_atom_init[] = +#define DEF(name, str) str "\0" +#include "quickjs-atom.h" +#undef DEF +; + +typedef enum OPCodeFormat { +#define FMT(f) OP_FMT_ ## f, +#define DEF(id, size, n_pop, n_push, f) +#include "quickjs-opcode.h" +#undef DEF +#undef FMT +} OPCodeFormat; + +typedef enum OPCodeEnum { +#define FMT(f) +#define DEF(id, size, n_pop, n_push, f) OP_ ## id, +#define def(id, size, n_pop, n_push, f) +#include "quickjs-opcode.h" +#undef def +#undef DEF +#undef FMT + OP_COUNT, /* excluding temporary opcodes */ + /* temporary opcodes : overlap with the short opcodes */ + OP_TEMP_START = OP_nop + 1, + OP___dummy = OP_TEMP_START - 1, +#define FMT(f) +#define DEF(id, size, n_pop, n_push, f) +#define def(id, size, n_pop, n_push, f) OP_ ## id, +#include "quickjs-opcode.h" +#undef def +#undef DEF +#undef FMT + OP_TEMP_END, +} OPCodeEnum; + +static int JS_InitAtoms(JSRuntime *rt); +static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, + int atom_type); +static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p); +static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b); +static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv, int flags); +static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv, int flags); +static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_obj, JSValueConst new_target, + int argc, JSValueConst *argv, int flags); +static JSValue JS_CallConstructorInternal(JSContext *ctx, + JSValueConst func_obj, + JSValueConst new_target, + int argc, JSValueConst *argv, int flags); +static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, + int argc, JSValueConst *argv); +static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, + int argc, JSValueConst *argv); +static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, + JSValue val, bool is_array_ctor); +static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, + JSValueConst val, int flags, int scope_idx); +static __maybe_unused void JS_DumpString(JSRuntime *rt, JSString *p); +static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt); +static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p); +static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p); +static __maybe_unused void JS_DumpValue(JSRuntime *rt, JSValueConst val); +static __maybe_unused void JS_DumpAtoms(JSRuntime *rt); +static __maybe_unused void JS_DumpShapes(JSRuntime *rt); + +static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic); +static void js_array_finalizer(JSRuntime *rt, JSValueConst val); +static void js_array_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_object_data_finalizer(JSRuntime *rt, JSValueConst val); +static void js_object_data_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_c_function_finalizer(JSRuntime *rt, JSValueConst val); +static void js_c_function_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_bytecode_function_finalizer(JSRuntime *rt, JSValueConst val); +static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_bound_function_finalizer(JSRuntime *rt, JSValueConst val); +static void js_bound_function_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValueConst val); +static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_regexp_finalizer(JSRuntime *rt, JSValueConst val); +static void js_array_buffer_finalizer(JSRuntime *rt, JSValueConst val); +static void js_typed_array_finalizer(JSRuntime *rt, JSValueConst val); +static void js_typed_array_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_proxy_finalizer(JSRuntime *rt, JSValueConst val); +static void js_proxy_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_map_finalizer(JSRuntime *rt, JSValueConst val); +static void js_map_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_map_iterator_finalizer(JSRuntime *rt, JSValueConst val); +static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_array_iterator_finalizer(JSRuntime *rt, JSValueConst val); +static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_iterator_concat_finalizer(JSRuntime *rt, JSValueConst val); +static void js_iterator_concat_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_iterator_helper_finalizer(JSRuntime *rt, JSValueConst val); +static void js_iterator_helper_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_iterator_wrap_finalizer(JSRuntime *rt, JSValueConst val); +static void js_iterator_wrap_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_regexp_string_iterator_finalizer(JSRuntime *rt, + JSValueConst val); +static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_generator_finalizer(JSRuntime *rt, JSValueConst val); +static void js_generator_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_promise_finalizer(JSRuntime *rt, JSValueConst val); +static void js_promise_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValueConst val); +static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); + +#define HINT_STRING 0 +#define HINT_NUMBER 1 +#define HINT_NONE 2 +#define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive +static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint); +static JSValue JS_ToStringFree(JSContext *ctx, JSValue val); +static int JS_ToBoolFree(JSContext *ctx, JSValue val); +static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val); +static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val); +static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val); +static JSValue JS_ToPropertyKeyInternal(JSContext *ctx, JSValueConst val, + int flags); +static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len); +static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, + JSValueConst flags); +static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, + JSValue pattern, JSValue bc); +static void gc_decref(JSRuntime *rt); +static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, + const JSClassDef *class_def, JSAtom name); +static JSValue js_array_push(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int unshift); +static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target, + int argc, JSValueConst *argv); +static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, + int argc, JSValueConst *argv, int magic); +static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic); + +typedef enum JSStrictEqModeEnum { + JS_EQ_STRICT, + JS_EQ_SAME_VALUE, + JS_EQ_SAME_VALUE_ZERO, +} JSStrictEqModeEnum; + +static bool js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, + JSStrictEqModeEnum eq_mode); +static bool js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2); +static bool js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2); +static bool js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2); +static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val); +static JSProperty *add_property(JSContext *ctx, + JSObject *p, JSAtom prop, int prop_flags); +static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); +static JSValue JS_ThrowStackOverflow(JSContext *ctx); +static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx); +static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj); +static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, + JSValueConst proto_val, bool throw_flag); +static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj); +static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj); +static int js_proxy_isArray(JSContext *ctx, JSValueConst obj); +static int JS_CreateProperty(JSContext *ctx, JSObject *p, + JSAtom prop, JSValueConst val, + JSValueConst getter, JSValueConst setter, + int flags); +static int js_string_memcmp(JSString *p1, JSString *p2, int len); +static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref); +static bool is_valid_weakref_target(JSValueConst val); +static void insert_weakref_record(JSValueConst target, + struct JSWeakRefRecord *wr); +static JSValue js_array_buffer_constructor3(JSContext *ctx, + JSValueConst new_target, + uint64_t len, uint64_t *max_len, + JSClassID class_id, + uint8_t *buf, + JSFreeArrayBufferDataFunc *free_func, + void *opaque, bool alloc_flag); +static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr); +static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj); +static bool array_buffer_is_resizable(const JSArrayBuffer *abuf); +static JSValue js_typed_array_constructor(JSContext *ctx, + JSValueConst this_val, + int argc, JSValueConst *argv, + int classid); +static JSValue js_typed_array_constructor_ta(JSContext *ctx, + JSValueConst new_target, + JSValueConst src_obj, + int classid, uint32_t len); +static bool is_typed_array(JSClassID class_id); +static bool typed_array_is_oob(JSObject *p); +static uint32_t typed_array_length(JSObject *p); +static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx); +static JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx); +static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx, + bool is_arg); +static JSValue js_call_generator_function(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv, + int flags); +static void js_async_function_resolve_finalizer(JSRuntime *rt, + JSValueConst val); +static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, + const char *input, size_t input_len, + const char *filename, int line, int flags, int scope_idx); +static void js_free_module_def(JSContext *ctx, JSModuleDef *m); +static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, + JS_MarkFunc *mark_func); +static JSValue js_import_meta(JSContext *ctx); +static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier); +static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref); +static JSValue js_new_promise_capability(JSContext *ctx, + JSValue *resolving_funcs, + JSValueConst ctor); +static __exception int perform_promise_then(JSContext *ctx, + JSValueConst promise, + JSValueConst *resolve_reject, + JSValueConst *cap_resolving_funcs); +static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic); +static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv); +static JSValue js_promise_resolve_thenable_job(JSContext *ctx, + int argc, JSValueConst *argv); +static bool js_string_eq(JSString *p1, JSString *p2); +static int js_string_compare(JSString *p1, JSString *p2); +static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, + JSValue prop, JSValue val, int flags); +static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val); +static bool JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val); +static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val); +static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, + JSObject *p, JSAtom prop); +static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc); +static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s, + JS_MarkFunc *mark_func); +static void JS_AddIntrinsicBasicObjects(JSContext *ctx); +static void js_free_shape(JSRuntime *rt, JSShape *sh); +static void js_free_shape_null(JSRuntime *rt, JSShape *sh); +static int js_shape_prepare_update(JSContext *ctx, JSObject *p, + JSShapeProperty **pprs); +static int init_shape_hash(JSRuntime *rt); +static __exception int js_get_length32(JSContext *ctx, uint32_t *pres, + JSValueConst obj); +static __exception int js_get_length64(JSContext *ctx, int64_t *pres, + JSValueConst obj); +static __exception int js_set_length64(JSContext *ctx, JSValueConst obj, + int64_t len); +static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len); +static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, + JSValueConst array_arg); +static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab); +static bool js_get_fast_array(JSContext *ctx, JSValue obj, + JSValue **arrpp, uint32_t *countp); +static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len); +static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx, + JSValue sync_iter); +static void js_c_function_data_finalizer(JSRuntime *rt, JSValueConst val); +static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); +static JSValue js_call_c_function_data(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_val, + int argc, JSValueConst *argv, int flags); +static void js_c_closure_finalizer(JSRuntime *rt, JSValueConst val); +static JSValue js_call_c_closure(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_val, + int argc, JSValueConst *argv, int flags); +static JSAtom js_symbol_to_atom(JSContext *ctx, JSValueConst val); +static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, + JSGCObjectTypeEnum type); +static void remove_gc_object(JSGCObjectHeader *h); +static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s); +static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); +static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, + void *opaque); +static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, + JSAtom atom, void *opaque); + +static void js_set_uncatchable_error(JSContext *ctx, JSValueConst val, + bool flag); + +static JSValue js_new_callsite(JSContext *ctx, JSCallSiteData *csd); +static void js_new_callsite_data(JSContext *ctx, JSCallSiteData *csd, JSStackFrame *sf); +static void js_new_callsite_data2(JSContext *ctx, JSCallSiteData *csd, const char *filename, int line_num, int col_num); +static void _JS_AddIntrinsicCallSite(JSContext *ctx); + +static void JS_SetOpaqueInternal(JSValueConst obj, void *opaque); + +static const JSClassExoticMethods js_arguments_exotic_methods; +static const JSClassExoticMethods js_string_exotic_methods; +static const JSClassExoticMethods js_proxy_exotic_methods; +static const JSClassExoticMethods js_module_ns_exotic_methods; + +static inline bool double_is_int32(double d) +{ + uint64_t u, e; + JSFloat64Union t; + + t.d = d; + u = t.u64; + + e = ((u >> 52) & 0x7FF) - 1023; + if (e > 30) { + // accept 0, INT32_MIN, reject too large, too small, nan, inf, -0 + return !u || (u == 0xc1e0000000000000); + } else { + // shift out sign, exponent and whole part bits + // value is fractional if remaining low bits are non-zero + return !(u << 12 << e); + } +} + +static JSValue js_float64(double d) +{ + return __JS_NewFloat64(d); +} + +static int compare_u32(uint32_t a, uint32_t b) +{ + return -(a < b) + (b < a); // -1, 0 or 1 +} + +static JSValue js_int32(int32_t v) +{ + return JS_MKVAL(JS_TAG_INT, v); +} + +static JSValue js_uint32(uint32_t v) +{ + if (v <= INT32_MAX) + return js_int32(v); + else + return js_float64(v); +} + +static JSValue js_int64(int64_t v) +{ + if (v >= INT32_MIN && v <= INT32_MAX) + return js_int32(v); + else + return js_float64(v); +} + +static JSValue js_number(double d) +{ + if (double_is_int32(d)) + return js_int32((int32_t)d); + else + return js_float64(d); +} + +JSValue JS_NewNumber(JSContext *ctx, double d) +{ + return js_number(d); +} + +static JSValue js_bool(bool v) +{ + return JS_MKVAL(JS_TAG_BOOL, (v != 0)); +} + +static JSValue js_dup(JSValueConst v) +{ + if (JS_VALUE_HAS_REF_COUNT(v)) { + JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); + p->ref_count++; + } + return unsafe_unconst(v); +} + +JSValue JS_DupValue(JSContext *ctx, JSValueConst v) +{ + return js_dup(v); +} + +JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v) +{ + return js_dup(v); +} + +static void js_trigger_gc(JSRuntime *rt, size_t size) +{ + bool force_gc; +#ifdef FORCE_GC_AT_MALLOC + force_gc = true; +#else + force_gc = ((rt->malloc_state.malloc_size + size) > + rt->malloc_gc_threshold); +#endif + if (force_gc) { +#ifdef ENABLE_DUMPS // JS_DUMP_GC + if (check_dump_flag(rt, JS_DUMP_GC)) { + printf("GC: size=%zd\n", rt->malloc_state.malloc_size); + } +#endif + JS_RunGC(rt); + rt->malloc_gc_threshold = rt->malloc_state.malloc_size + + (rt->malloc_state.malloc_size >> 1); + } +} + +static size_t js_malloc_usable_size_unknown(const void *ptr) +{ + return 0; +} + +void *js_calloc_rt(JSRuntime *rt, size_t count, size_t size) +{ + void *ptr; + JSMallocState *s; + + /* Do not allocate zero bytes: behavior is platform dependent */ + assert(count != 0 && size != 0); + + if (size > 0) + if (unlikely(count != (count * size) / size)) + return NULL; + + s = &rt->malloc_state; + /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */ + if (unlikely(s->malloc_size + (count * size) > s->malloc_limit - 1)) + return NULL; + + ptr = rt->mf.js_calloc(s->opaque, count, size); + if (!ptr) + return NULL; + + s->malloc_count++; + s->malloc_size += rt->mf.js_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + return ptr; +} + +void *js_malloc_rt(JSRuntime *rt, size_t size) +{ + void *ptr; + JSMallocState *s; + + /* Do not allocate zero bytes: behavior is platform dependent */ + assert(size != 0); + + s = &rt->malloc_state; + /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */ + if (unlikely(s->malloc_size + size > s->malloc_limit - 1)) + return NULL; + + ptr = rt->mf.js_malloc(s->opaque, size); + if (!ptr) + return NULL; + + s->malloc_count++; + s->malloc_size += rt->mf.js_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + return ptr; +} + +void js_free_rt(JSRuntime *rt, void *ptr) +{ + JSMallocState *s; + + if (!ptr) + return; + + s = &rt->malloc_state; + s->malloc_count--; + s->malloc_size -= rt->mf.js_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + rt->mf.js_free(s->opaque, ptr); +} + +void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size) +{ + size_t old_size; + JSMallocState *s; + + if (!ptr) { + if (size == 0) + return NULL; + return js_malloc_rt(rt, size); + } + if (unlikely(size == 0)) { + js_free_rt(rt, ptr); + return NULL; + } + old_size = rt->mf.js_malloc_usable_size(ptr); + s = &rt->malloc_state; + /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */ + if (s->malloc_size + size - old_size > s->malloc_limit - 1) + return NULL; + + ptr = rt->mf.js_realloc(s->opaque, ptr, size); + if (!ptr) + return NULL; + + s->malloc_size += rt->mf.js_malloc_usable_size(ptr) - old_size; + return ptr; +} + +size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr) +{ + return rt->mf.js_malloc_usable_size(ptr); +} + +/** + * This used to be implemented as malloc + memset, but using calloc + * yields better performance in initial, bursty allocations, something useful + * for QuickJS. + * + * More information: https://github.com/quickjs-ng/quickjs/pull/519 + */ +void *js_mallocz_rt(JSRuntime *rt, size_t size) +{ + return js_calloc_rt(rt, 1, size); +} + +/* Throw out of memory in case of error */ +void *js_calloc(JSContext *ctx, size_t count, size_t size) +{ + void *ptr; + ptr = js_calloc_rt(ctx->rt, count, size); + if (unlikely(!ptr)) { + JS_ThrowOutOfMemory(ctx); + return NULL; + } + return ptr; +} + +/* Throw out of memory in case of error */ +void *js_malloc(JSContext *ctx, size_t size) +{ + void *ptr; + ptr = js_malloc_rt(ctx->rt, size); + if (unlikely(!ptr)) { + JS_ThrowOutOfMemory(ctx); + return NULL; + } + return ptr; +} + +/* Throw out of memory in case of error */ +void *js_mallocz(JSContext *ctx, size_t size) +{ + void *ptr; + ptr = js_mallocz_rt(ctx->rt, size); + if (unlikely(!ptr)) { + JS_ThrowOutOfMemory(ctx); + return NULL; + } + return ptr; +} + +void js_free(JSContext *ctx, void *ptr) +{ + js_free_rt(ctx->rt, ptr); +} + +/* Throw out of memory in case of error */ +void *js_realloc(JSContext *ctx, void *ptr, size_t size) +{ + void *ret; + ret = js_realloc_rt(ctx->rt, ptr, size); + if (unlikely(!ret && size != 0)) { + JS_ThrowOutOfMemory(ctx); + return NULL; + } + return ret; +} + +/* store extra allocated size in *pslack if successful */ +void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack) +{ + void *ret; + ret = js_realloc_rt(ctx->rt, ptr, size); + if (unlikely(!ret && size != 0)) { + JS_ThrowOutOfMemory(ctx); + return NULL; + } + if (pslack) { + size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret); + *pslack = (new_size > size) ? new_size - size : 0; + } + return ret; +} + +size_t js_malloc_usable_size(JSContext *ctx, const void *ptr) +{ + return js_malloc_usable_size_rt(ctx->rt, ptr); +} + +/* Throw out of memory exception in case of error */ +char *js_strndup(JSContext *ctx, const char *s, size_t n) +{ + char *ptr; + ptr = js_malloc(ctx, n + 1); + if (ptr) { + memcpy(ptr, s, n); + ptr[n] = '\0'; + } + return ptr; +} + +char *js_strdup(JSContext *ctx, const char *str) +{ + return js_strndup(ctx, str, strlen(str)); +} + +static no_inline int js_realloc_array(JSContext *ctx, void **parray, + int elem_size, int *psize, int req_size) +{ + int new_size; + size_t slack; + void *new_array; + /* XXX: potential arithmetic overflow */ + new_size = max_int(req_size, *psize * 3 / 2); + new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack); + if (!new_array) + return -1; + new_size += slack / elem_size; + *psize = new_size; + *parray = new_array; + return 0; +} + +/* resize the array and update its size if req_size > *psize */ +static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size, + int *psize, int req_size) +{ + if (unlikely(req_size > *psize)) + return js_realloc_array(ctx, parray, elem_size, psize, req_size); + else + return 0; +} + +static void *js_dbuf_realloc(void *ctx, void *ptr, size_t size) +{ + return js_realloc(ctx, ptr, size); +} + +static inline void js_dbuf_init(JSContext *ctx, DynBuf *s) +{ + dbuf_init2(s, ctx, js_dbuf_realloc); +} + +static inline int is_digit(int c) { + return c >= '0' && c <= '9'; +} + +static inline int string_get(JSString *p, int idx) { + return p->is_wide_char ? str16(p)[idx] : str8(p)[idx]; +} + +typedef struct JSClassShortDef { + JSAtom class_name; + JSClassFinalizer *finalizer; + JSClassGCMark *gc_mark; +} JSClassShortDef; + +static JSClassShortDef const js_std_class_def[] = { + { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_OBJECT */ + { JS_ATOM_Array, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARRAY */ + { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */ + { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */ + { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */ + { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */ + { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */ + { JS_ATOM_Arguments, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARGUMENTS */ + { JS_ATOM_Arguments, NULL, NULL }, /* JS_CLASS_MAPPED_ARGUMENTS */ + { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */ + { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_MODULE_NS */ + { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */ + { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */ + { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */ + { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */ + { JS_ATOM_Function, js_c_closure_finalizer, NULL}, /* JS_CLASS_C_CLOSURE */ + { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_GENERATOR_FUNCTION */ + { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark }, /* JS_CLASS_FOR_IN_ITERATOR */ + { JS_ATOM_RegExp, js_regexp_finalizer, NULL }, /* JS_CLASS_REGEXP */ + { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL }, /* JS_CLASS_ARRAY_BUFFER */ + { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL }, /* JS_CLASS_SHARED_ARRAY_BUFFER */ + { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */ + { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT8_ARRAY */ + { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8_ARRAY */ + { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT16_ARRAY */ + { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT16_ARRAY */ + { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT32_ARRAY */ + { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT32_ARRAY */ + { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_INT64_ARRAY */ + { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_UINT64_ARRAY */ + { JS_ATOM_Float16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT16_ARRAY */ + { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT32_ARRAY */ + { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT64_ARRAY */ + { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_DATAVIEW */ + { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */ + { JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */ + { JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */ + { JS_ATOM_WeakMap, js_map_finalizer, NULL }, /* JS_CLASS_WEAKMAP */ + { JS_ATOM_WeakSet, js_map_finalizer, NULL }, /* JS_CLASS_WEAKSET */ + { JS_ATOM_Iterator, NULL, NULL }, /* JS_CLASS_ITERATOR */ + { JS_ATOM_IteratorConcat, js_iterator_concat_finalizer, js_iterator_concat_mark }, /* JS_CLASS_ITERATOR_CONCAT */ + { JS_ATOM_IteratorHelper, js_iterator_helper_finalizer, js_iterator_helper_mark }, /* JS_CLASS_ITERATOR_HELPER */ + { JS_ATOM_IteratorWrap, js_iterator_wrap_finalizer, js_iterator_wrap_mark }, /* JS_CLASS_ITERATOR_WRAP */ + { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */ + { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */ + { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */ + { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */ + { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */ + { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */ +}; + +static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab, + int start, int count) +{ + JSClassDef cm_s, *cm = &cm_s; + int i, class_id; + + for(i = 0; i < count; i++) { + class_id = i + start; + memset(cm, 0, sizeof(*cm)); + cm->finalizer = tab[i].finalizer; + cm->gc_mark = tab[i].gc_mark; + if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0) + return -1; + } + return 0; +} + +/* Uses code from LLVM project. */ +static inline uintptr_t js_get_stack_pointer(void) +{ +#if defined(__clang__) || defined(__GNUC__) + return (uintptr_t)__builtin_frame_address(0); +#elif defined(_MSC_VER) + return (uintptr_t)_AddressOfReturnAddress(); +#else + char CharOnStack = 0; + // The volatile store here is intended to escape the local variable, to + // prevent the compiler from optimizing CharOnStack into anything other + // than a char on the stack. + // + // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19. + char *volatile Ptr = &CharOnStack; + return (uintptr_t) Ptr; +#endif +} + +static inline bool js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) +{ + uintptr_t sp; + sp = js_get_stack_pointer() - alloca_size; + return unlikely(sp < rt->stack_limit); +} + +JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) +{ + JSRuntime *rt; + JSMallocState ms; + + memset(&ms, 0, sizeof(ms)); + ms.opaque = opaque; + ms.malloc_limit = 0; + + rt = mf->js_calloc(opaque, 1, sizeof(JSRuntime)); + if (!rt) + return NULL; + rt->mf = *mf; + if (!rt->mf.js_malloc_usable_size) { + /* use dummy function if none provided */ + rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown; + } + /* Inline what js_malloc_rt does since we cannot use it here. */ + ms.malloc_count++; + ms.malloc_size += rt->mf.js_malloc_usable_size(rt) + MALLOC_OVERHEAD; + rt->malloc_state = ms; + rt->malloc_gc_threshold = 256 * 1024; + + init_list_head(&rt->context_list); + init_list_head(&rt->gc_obj_list); + init_list_head(&rt->gc_zero_ref_count_list); + rt->gc_phase = JS_GC_PHASE_NONE; + +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + init_list_head(&rt->string_list); +#endif + init_list_head(&rt->job_list); + + if (JS_InitAtoms(rt)) + goto fail; + + /* create the object, array and function classes */ + if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT, + countof(js_std_class_def)) < 0) + goto fail; + rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods; + rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods; + rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods; + + rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function; + rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_call_c_function_data; + rt->class_array[JS_CLASS_C_CLOSURE].call = js_call_c_closure; + rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function; + rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_call_generator_function; + if (init_shape_hash(rt)) + goto fail; + + rt->js_class_id_alloc = JS_CLASS_INIT_COUNT; + + rt->stack_size = JS_DEFAULT_STACK_SIZE; +#ifdef __wasi__ + rt->stack_size = 0; +#endif + + JS_UpdateStackTop(rt); + + rt->current_exception = JS_UNINITIALIZED; + + return rt; + fail: + JS_FreeRuntime(rt); + return NULL; +} + +void *JS_GetRuntimeOpaque(JSRuntime *rt) +{ + return rt->user_opaque; +} + +void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque) +{ + rt->user_opaque = opaque; +} + +int JS_AddRuntimeFinalizer(JSRuntime *rt, JSRuntimeFinalizer *finalizer, + void *arg) +{ + JSRuntimeFinalizerState *fs = js_malloc_rt(rt, sizeof(*fs)); + if (!fs) + return -1; + fs->next = rt->finalizers; + fs->finalizer = finalizer; + fs->arg = arg; + rt->finalizers = fs; + return 0; +} + +static void *js_def_calloc(void *opaque, size_t count, size_t size) +{ + return calloc(count, size); +} + +static void *js_def_malloc(void *opaque, size_t size) +{ + return malloc(size); +} + +static void js_def_free(void *opaque, void *ptr) +{ + free(ptr); +} + +static void *js_def_realloc(void *opaque, void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +static const JSMallocFunctions def_malloc_funcs = { + js_def_calloc, + js_def_malloc, + js_def_free, + js_def_realloc, + js__malloc_usable_size +}; + +JSRuntime *JS_NewRuntime(void) +{ + return JS_NewRuntime2(&def_malloc_funcs, NULL); +} + +void JS_SetMemoryLimit(JSRuntime *rt, size_t limit) +{ + rt->malloc_state.malloc_limit = limit; +} + +void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags) +{ +#ifdef ENABLE_DUMPS + rt->dump_flags = flags; +#endif +} + +uint64_t JS_GetDumpFlags(JSRuntime *rt) +{ +#ifdef ENABLE_DUMPS + return rt->dump_flags; +#else + return 0; +#endif +} + +size_t JS_GetGCThreshold(JSRuntime *rt) { + return rt->malloc_gc_threshold; +} + +/* use -1 to disable automatic GC */ +void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold) +{ + rt->malloc_gc_threshold = gc_threshold; +} + +#define malloc(s) malloc_is_forbidden(s) +#define free(p) free_is_forbidden(p) +#define realloc(p,s) realloc_is_forbidden(p,s) + +void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque) +{ + rt->interrupt_handler = cb; + rt->interrupt_opaque = opaque; +} + +void JS_SetCanBlock(JSRuntime *rt, bool can_block) +{ + rt->can_block = can_block; +} + +void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, + const JSSharedArrayBufferFunctions *sf) +{ + rt->sab_funcs = *sf; +} + +/* return 0 if OK, < 0 if exception */ +int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = ctx->rt; + JSJobEntry *e; + int i; + + assert(!rt->in_free); + + e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue)); + if (!e) + return -1; + e->ctx = ctx; + e->job_func = job_func; + e->argc = argc; + for(i = 0; i < argc; i++) { + e->argv[i] = js_dup(argv[i]); + } + list_add_tail(&e->link, &rt->job_list); + return 0; +} + +bool JS_IsJobPending(JSRuntime *rt) +{ + return !list_empty(&rt->job_list); +} + +/* return < 0 if exception, 0 if no job pending, 1 if a job was + executed successfully. the context of the job is stored in '*pctx' */ +int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx) +{ + JSContext *ctx; + JSJobEntry *e; + JSValue res; + int i, ret; + + if (list_empty(&rt->job_list)) { + *pctx = NULL; + return 0; + } + + /* get the first pending job and execute it */ + e = list_entry(rt->job_list.next, JSJobEntry, link); + list_del(&e->link); + ctx = e->ctx; + res = e->job_func(e->ctx, e->argc, vc(e->argv)); + for(i = 0; i < e->argc; i++) + JS_FreeValue(ctx, e->argv[i]); + if (JS_IsException(res)) + ret = -1; + else + ret = 1; + JS_FreeValue(ctx, res); + js_free(ctx, e); + *pctx = ctx; + return ret; +} + +static inline uint32_t atom_get_free(const JSAtomStruct *p) +{ + return (uintptr_t)p >> 1; +} + +static inline bool atom_is_free(const JSAtomStruct *p) +{ + return (uintptr_t)p & 1; +} + +static inline JSAtomStruct *atom_set_free(uint32_t v) +{ + return (JSAtomStruct *)(((uintptr_t)v << 1) | 1); +} + +/* Note: the string contents are uninitialized */ +static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char) +{ + JSString *str; + str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char); + if (unlikely(!str)) + return NULL; + str->header.ref_count = 1; + str->is_wide_char = is_wide_char; + str->len = max_len; + str->kind = JS_STRING_KIND_NORMAL; + str->atom_type = 0; + str->hash = 0; /* optional but costless */ + str->hash_next = 0; /* optional */ +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + list_add_tail(&str->link, &rt->string_list); +#endif + return str; +} + +static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char) +{ + JSString *p; + p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char); + if (unlikely(!p)) { + JS_ThrowOutOfMemory(ctx); + return NULL; + } + return p; +} + +static inline void js_free_string0(JSRuntime *rt, JSString *str); + +/* same as JS_FreeValueRT() but faster */ +static inline void js_free_string(JSRuntime *rt, JSString *str) +{ + if (--str->header.ref_count <= 0) + js_free_string0(rt, str); +} + +static inline void js_free_string0(JSRuntime *rt, JSString *str) +{ + if (str->atom_type) { + JS_FreeAtomStruct(rt, str); + } else { +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + list_del(&str->link); +#endif + if (str->kind == JS_STRING_KIND_SLICE) { + JSStringSlice *slice = (void *)&str[1]; + js_free_string(rt, slice->parent); // safe, recurses only 1 level + } + js_free_rt(rt, str); + } +} + +void JS_SetRuntimeInfo(JSRuntime *rt, const char *s) +{ + if (rt) + rt->rt_info = s; +} + +void JS_FreeRuntime(JSRuntime *rt) +{ + struct list_head *el, *el1; + int i; + + rt->in_free = true; + JS_FreeValueRT(rt, rt->current_exception); + + list_for_each_safe(el, el1, &rt->job_list) { + JSJobEntry *e = list_entry(el, JSJobEntry, link); + for(i = 0; i < e->argc; i++) + JS_FreeValueRT(rt, e->argv[i]); + js_free_rt(rt, e); + } + init_list_head(&rt->job_list); + + JS_RunGC(rt); + +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + /* leaking objects */ + if (check_dump_flag(rt, JS_DUMP_LEAKS)) { + bool header_done; + JSGCObjectHeader *p; + int count; + + /* remove the internal refcounts to display only the object + referenced externally */ + list_for_each(el, &rt->gc_obj_list) { + p = list_entry(el, JSGCObjectHeader, link); + p->mark = 0; + } + gc_decref(rt); + + header_done = false; + list_for_each(el, &rt->gc_obj_list) { + p = list_entry(el, JSGCObjectHeader, link); + if (p->ref_count != 0) { + if (!header_done) { + printf("Object leaks:\n"); + JS_DumpObjectHeader(rt); + header_done = true; + } + JS_DumpGCObject(rt, p); + } + } + + count = 0; + list_for_each(el, &rt->gc_obj_list) { + p = list_entry(el, JSGCObjectHeader, link); + if (p->ref_count == 0) { + count++; + } + } + if (count != 0) + printf("Secondary object leaks: %d\n", count); + } +#endif + + assert(list_empty(&rt->gc_obj_list)); + + /* free the classes */ + for(i = 0; i < rt->class_count; i++) { + JSClass *cl = &rt->class_array[i]; + if (cl->class_id != 0) { + JS_FreeAtomRT(rt, cl->class_name); + } + } + js_free_rt(rt, rt->class_array); + +#ifdef ENABLE_DUMPS // JS_DUMP_ATOM_LEAKS + /* only the atoms defined in JS_InitAtoms() should be left */ + if (check_dump_flag(rt, JS_DUMP_ATOM_LEAKS)) { + bool header_done = false; + + for(i = 0; i < rt->atom_size; i++) { + JSAtomStruct *p = rt->atom_array[i]; + if (!atom_is_free(p) /* && p->str*/) { + if (i >= JS_ATOM_END || p->header.ref_count != 1) { + if (!header_done) { + header_done = true; + if (rt->rt_info) { + printf("%s:1: atom leakage:", rt->rt_info); + } else { + printf("Atom leaks:\n" + " %6s %6s %s\n", + "ID", "REFCNT", "NAME"); + } + } + if (rt->rt_info) { + printf(" "); + } else { + printf(" %6u %6u ", i, p->header.ref_count); + } + switch (p->atom_type) { + case JS_ATOM_TYPE_STRING: + JS_DumpString(rt, p); + break; + case JS_ATOM_TYPE_GLOBAL_SYMBOL: + printf("Symbol.for("); + JS_DumpString(rt, p); + printf(")"); + break; + case JS_ATOM_TYPE_SYMBOL: + if (p->hash == JS_ATOM_HASH_SYMBOL) { + printf("Symbol("); + JS_DumpString(rt, p); + printf(")"); + } else { + printf("Private("); + JS_DumpString(rt, p); + printf(")"); + } + break; + } + if (rt->rt_info) { + printf(":%u", p->header.ref_count); + } else { + printf("\n"); + } + } + } + } + if (rt->rt_info && header_done) + printf("\n"); + } +#endif + + /* free the atoms */ + for(i = 0; i < rt->atom_size; i++) { + JSAtomStruct *p = rt->atom_array[i]; + if (!atom_is_free(p)) { +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + list_del(&p->link); +#endif + js_free_rt(rt, p); + } + } + js_free_rt(rt, rt->atom_array); + js_free_rt(rt, rt->atom_hash); + js_free_rt(rt, rt->shape_hash); +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + if (check_dump_flag(rt, JS_DUMP_LEAKS) && !list_empty(&rt->string_list)) { + if (rt->rt_info) { + printf("%s:1: string leakage:", rt->rt_info); + } else { + printf("String leaks:\n" + " %6s %s\n", + "REFCNT", "VALUE"); + } + list_for_each_safe(el, el1, &rt->string_list) { + JSString *str = list_entry(el, JSString, link); + if (rt->rt_info) { + printf(" "); + } else { + printf(" %6u ", str->header.ref_count); + } + JS_DumpString(rt, str); + if (rt->rt_info) { + printf(":%u", str->header.ref_count); + } else { + printf("\n"); + } + list_del(&str->link); + js_free_rt(rt, str); + } + if (rt->rt_info) + printf("\n"); + } +#endif + + while (rt->finalizers) { + JSRuntimeFinalizerState *fs = rt->finalizers; + rt->finalizers = fs->next; + fs->finalizer(rt, fs->arg); + js_free_rt(rt, fs); + } + +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + if (check_dump_flag(rt, JS_DUMP_LEAKS)) { + JSMallocState *s = &rt->malloc_state; + if (s->malloc_count > 1) { + if (rt->rt_info) + printf("%s:1: ", rt->rt_info); + printf("Memory leak: %zd bytes lost in %zd block%s\n", + s->malloc_size - sizeof(JSRuntime), + s->malloc_count - 1, &"s"[s->malloc_count == 2]); + } + } +#endif + + { + JSMallocState *ms = &rt->malloc_state; + rt->mf.js_free(ms->opaque, rt); + } +} + +JSContext *JS_NewContextRaw(JSRuntime *rt) +{ + JSContext *ctx; + int i; + + ctx = js_mallocz_rt(rt, sizeof(JSContext)); + if (!ctx) + return NULL; + ctx->header.ref_count = 1; + add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT); + + ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) * + rt->class_count); + if (!ctx->class_proto) { + js_free_rt(rt, ctx); + return NULL; + } + ctx->rt = rt; + list_add_tail(&ctx->link, &rt->context_list); + for(i = 0; i < rt->class_count; i++) + ctx->class_proto[i] = JS_NULL; + ctx->array_ctor = JS_NULL; + ctx->iterator_ctor = JS_NULL; + ctx->iterator_ctor_getset = JS_NULL; + ctx->regexp_ctor = JS_NULL; + ctx->promise_ctor = JS_NULL; + ctx->error_ctor = JS_NULL; + ctx->error_back_trace = JS_UNDEFINED; + ctx->error_prepare_stack = JS_UNDEFINED; + ctx->error_stack_trace_limit = js_int32(10); + init_list_head(&ctx->loaded_modules); + + JS_AddIntrinsicBasicObjects(ctx); + return ctx; +} + +JSContext *JS_NewContext(JSRuntime *rt) +{ + JSContext *ctx; + + ctx = JS_NewContextRaw(rt); + if (!ctx) + return NULL; + + JS_AddIntrinsicBaseObjects(ctx); + JS_AddIntrinsicDate(ctx); + JS_AddIntrinsicEval(ctx); + JS_AddIntrinsicRegExp(ctx); + JS_AddIntrinsicJSON(ctx); + JS_AddIntrinsicProxy(ctx); + JS_AddIntrinsicMapSet(ctx); + JS_AddIntrinsicTypedArrays(ctx); + JS_AddIntrinsicPromise(ctx); + JS_AddIntrinsicBigInt(ctx); + JS_AddIntrinsicWeakRef(ctx); + JS_AddIntrinsicDOMException(ctx); + + JS_AddPerformance(ctx); + + return ctx; +} + +void *JS_GetContextOpaque(JSContext *ctx) +{ + return ctx->user_opaque; +} + +void JS_SetContextOpaque(JSContext *ctx, void *opaque) +{ + ctx->user_opaque = opaque; +} + +/* set the new value and free the old value after (freeing the value + can reallocate the object data) */ +static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val) +{ + JSValue old_val; + old_val = *pval; + *pval = new_val; + JS_FreeValue(ctx, old_val); +} + +void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj) +{ + assert(class_id < ctx->rt->class_count); + set_value(ctx, &ctx->class_proto[class_id], obj); +} + +JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id) +{ + assert(class_id < ctx->rt->class_count); + return js_dup(ctx->class_proto[class_id]); +} + +JSValue JS_GetFunctionProto(JSContext *ctx) +{ + return js_dup(ctx->function_proto); +} + +typedef enum JSFreeModuleEnum { + JS_FREE_MODULE_ALL, + JS_FREE_MODULE_NOT_RESOLVED, +} JSFreeModuleEnum; + +/* XXX: would be more efficient with separate module lists */ +static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag) +{ + struct list_head *el, *el1; + list_for_each_safe(el, el1, &ctx->loaded_modules) { + JSModuleDef *m = list_entry(el, JSModuleDef, link); + if (flag == JS_FREE_MODULE_ALL || + (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) { + js_free_module_def(ctx, m); + } + } +} + +JSContext *JS_DupContext(JSContext *ctx) +{ + ctx->header.ref_count++; + return ctx; +} + +/* used by the GC */ +static void JS_MarkContext(JSRuntime *rt, JSContext *ctx, + JS_MarkFunc *mark_func) +{ + int i; + struct list_head *el; + + /* modules are not seen by the GC, so we directly mark the objects + referenced by each module */ + list_for_each(el, &ctx->loaded_modules) { + JSModuleDef *m = list_entry(el, JSModuleDef, link); + js_mark_module_def(rt, m, mark_func); + } + + JS_MarkValue(rt, ctx->global_obj, mark_func); + JS_MarkValue(rt, ctx->global_var_obj, mark_func); + + JS_MarkValue(rt, ctx->throw_type_error, mark_func); + JS_MarkValue(rt, ctx->eval_obj, mark_func); + + JS_MarkValue(rt, ctx->array_proto_values, mark_func); + for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { + JS_MarkValue(rt, ctx->native_error_proto[i], mark_func); + } + JS_MarkValue(rt, ctx->error_ctor, mark_func); + JS_MarkValue(rt, ctx->error_back_trace, mark_func); + JS_MarkValue(rt, ctx->error_prepare_stack, mark_func); + JS_MarkValue(rt, ctx->error_stack_trace_limit, mark_func); + for(i = 0; i < rt->class_count; i++) { + JS_MarkValue(rt, ctx->class_proto[i], mark_func); + } + JS_MarkValue(rt, ctx->iterator_ctor, mark_func); + JS_MarkValue(rt, ctx->iterator_ctor_getset, mark_func); + JS_MarkValue(rt, ctx->async_iterator_proto, mark_func); + JS_MarkValue(rt, ctx->promise_ctor, mark_func); + JS_MarkValue(rt, ctx->array_ctor, mark_func); + JS_MarkValue(rt, ctx->regexp_ctor, mark_func); + JS_MarkValue(rt, ctx->function_ctor, mark_func); + JS_MarkValue(rt, ctx->function_proto, mark_func); + + if (ctx->array_shape) + mark_func(rt, &ctx->array_shape->header); +} + +void JS_FreeContext(JSContext *ctx) +{ + JSRuntime *rt = ctx->rt; + int i; + + if (--ctx->header.ref_count > 0) + return; + assert(ctx->header.ref_count == 0); + +#ifdef ENABLE_DUMPS // JS_DUMP_ATOMS + if (check_dump_flag(rt, JS_DUMP_ATOMS)) + JS_DumpAtoms(ctx->rt); +#endif +#ifdef ENABLE_DUMPS // JS_DUMP_SHAPES + if (check_dump_flag(rt, JS_DUMP_SHAPES)) + JS_DumpShapes(ctx->rt); +#endif +#ifdef ENABLE_DUMPS // JS_DUMP_OBJECTS + if (check_dump_flag(rt, JS_DUMP_OBJECTS)) { + struct list_head *el; + JSGCObjectHeader *p; + printf("JSObjects: {\n"); + JS_DumpObjectHeader(ctx->rt); + list_for_each(el, &rt->gc_obj_list) { + p = list_entry(el, JSGCObjectHeader, link); + JS_DumpGCObject(rt, p); + } + printf("}\n"); + } +#endif +#ifdef ENABLE_DUMPS // JS_DUMP_MEM + if (check_dump_flag(rt, JS_DUMP_MEM)) { + JSMemoryUsage stats; + JS_ComputeMemoryUsage(rt, &stats); + JS_DumpMemoryUsage(stdout, &stats, rt); + } +#endif + + js_free_modules(ctx, JS_FREE_MODULE_ALL); + + JS_FreeValue(ctx, ctx->global_obj); + JS_FreeValue(ctx, ctx->global_var_obj); + + JS_FreeValue(ctx, ctx->throw_type_error); + JS_FreeValue(ctx, ctx->eval_obj); + + JS_FreeValue(ctx, ctx->array_proto_values); + for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { + JS_FreeValue(ctx, ctx->native_error_proto[i]); + } + JS_FreeValue(ctx, ctx->error_ctor); + JS_FreeValue(ctx, ctx->error_back_trace); + JS_FreeValue(ctx, ctx->error_prepare_stack); + JS_FreeValue(ctx, ctx->error_stack_trace_limit); + for(i = 0; i < rt->class_count; i++) { + JS_FreeValue(ctx, ctx->class_proto[i]); + } + js_free_rt(rt, ctx->class_proto); + JS_FreeValue(ctx, ctx->iterator_ctor); + JS_FreeValue(ctx, ctx->iterator_ctor_getset); + JS_FreeValue(ctx, ctx->async_iterator_proto); + JS_FreeValue(ctx, ctx->promise_ctor); + JS_FreeValue(ctx, ctx->array_ctor); + JS_FreeValue(ctx, ctx->regexp_ctor); + JS_FreeValue(ctx, ctx->function_ctor); + JS_FreeValue(ctx, ctx->function_proto); + + js_free_shape_null(ctx->rt, ctx->array_shape); + + list_del(&ctx->link); + remove_gc_object(&ctx->header); + js_free_rt(ctx->rt, ctx); +} + +JSRuntime *JS_GetRuntime(JSContext *ctx) +{ + return ctx->rt; +} + +static void update_stack_limit(JSRuntime *rt) +{ + /* SAU-103: honor explicit stack limits on WASI as on other targets. */ + if (rt->stack_size == 0) { + rt->stack_limit = 0; /* no limit */ + } else { + rt->stack_limit = rt->stack_top - rt->stack_size; + } +} + +void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size) +{ + rt->stack_size = stack_size; + update_stack_limit(rt); +} + +void JS_UpdateStackTop(JSRuntime *rt) +{ + rt->stack_top = js_get_stack_pointer(); + update_stack_limit(rt); +} + +static inline bool is_strict_mode(JSContext *ctx) +{ + JSStackFrame *sf = ctx->rt->current_stack_frame; + return sf && sf->is_strict_mode; +} + +/* JSAtom support */ + +#define JS_ATOM_TAG_INT (1U << 31) +#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1) +#define JS_ATOM_MAX ((1U << 30) - 1) + +/* return the max count from the hash size */ +#define JS_ATOM_COUNT_RESIZE(n) ((n) * 2) + +static inline bool __JS_AtomIsConst(JSAtom v) +{ + return (int32_t)v < JS_ATOM_END; +} + +static inline bool __JS_AtomIsTaggedInt(JSAtom v) +{ + return (v & JS_ATOM_TAG_INT) != 0; +} + +static inline JSAtom __JS_AtomFromUInt32(uint32_t v) +{ + return v | JS_ATOM_TAG_INT; +} + +static inline uint32_t __JS_AtomToUInt32(JSAtom atom) +{ + return atom & ~JS_ATOM_TAG_INT; +} + +static inline int is_num(int c) +{ + return c >= '0' && c <= '9'; +} + +/* return true if the string is a number n with 0 <= n <= 2^32-1 */ +static inline bool is_num_string(uint32_t *pval, JSString *p) +{ + uint32_t n; + uint64_t n64; + int c, i, len; + + len = p->len; + if (len == 0 || len > 10) + return false; + c = string_get(p, 0); + if (is_num(c)) { + if (c == '0') { + if (len != 1) + return false; + n = 0; + } else { + n = c - '0'; + for(i = 1; i < len; i++) { + c = string_get(p, i); + if (!is_num(c)) + return false; + n64 = (uint64_t)n * 10 + (c - '0'); + if ((n64 >> 32) != 0) + return false; + n = n64; + } + } + *pval = n; + return true; + } else { + return false; + } +} + +/* XXX: could use faster version ? */ +static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h) +{ + size_t i; + + for(i = 0; i < len; i++) + h = h * 263 + str[i]; + return h; +} + +static inline uint32_t hash_string16(const uint16_t *str, + size_t len, uint32_t h) +{ + size_t i; + + for(i = 0; i < len; i++) + h = h * 263 + str[i]; + return h; +} + +static uint32_t hash_string(JSString *str, uint32_t h) +{ + if (str->is_wide_char) + h = hash_string16(str16(str), str->len, h); + else + h = hash_string8(str8(str), str->len, h); + return h; +} + +static __maybe_unused void JS_DumpString(JSRuntime *rt, JSString *p) +{ + int i, c, sep; + + if (p == NULL) { + printf(""); + return; + } + if (p->header.ref_count != 1) + printf("%d", p->header.ref_count); + if (p->is_wide_char) + putchar('L'); + sep = '\"'; + putchar(sep); + for(i = 0; i < p->len; i++) { + c = string_get(p, i); + if (c == sep || c == '\\') { + putchar('\\'); + putchar(c); + } else if (c >= ' ' && c <= 126) { + putchar(c); + } else if (c == '\n') { + putchar('\\'); + putchar('n'); + } else { + printf("\\u%04x", c); + } + } + putchar(sep); +} + +static __maybe_unused void JS_DumpAtoms(JSRuntime *rt) +{ + JSAtomStruct *p; + int h, i; + /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */ + printf("JSAtom count=%d size=%d hash_size=%d:\n", + rt->atom_count, rt->atom_size, rt->atom_hash_size); + printf("JSAtom hash table: {\n"); + for(i = 0; i < rt->atom_hash_size; i++) { + h = rt->atom_hash[i]; + if (h) { + printf(" %d:", i); + while (h) { + p = rt->atom_array[h]; + printf(" "); + JS_DumpString(rt, p); + h = p->hash_next; + } + printf("\n"); + } + } + printf("}\n"); + printf("JSAtom table: {\n"); + for(i = 0; i < rt->atom_size; i++) { + p = rt->atom_array[i]; + if (!atom_is_free(p)) { + printf(" %d: { %d %08x ", i, p->atom_type, p->hash); + if (!(p->len == 0 && p->is_wide_char != 0)) + JS_DumpString(rt, p); + printf(" %d }\n", p->hash_next); + } + } + printf("}\n"); +} + +static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size) +{ + JSAtomStruct *p; + uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash; + + assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */ + new_hash_mask = new_hash_size - 1; + new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size); + if (!new_hash) + return -1; + for(i = 0; i < rt->atom_hash_size; i++) { + h = rt->atom_hash[i]; + while (h != 0) { + p = rt->atom_array[h]; + hash_next1 = p->hash_next; + /* add in new hash table */ + j = p->hash & new_hash_mask; + p->hash_next = new_hash[j]; + new_hash[j] = h; + h = hash_next1; + } + } + js_free_rt(rt, rt->atom_hash); + rt->atom_hash = new_hash; + rt->atom_hash_size = new_hash_size; + rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size); + // JS_DumpAtoms(rt); + return 0; +} + +static int JS_InitAtoms(JSRuntime *rt) +{ + int i, len, atom_type; + const char *p; + + rt->atom_hash_size = 0; + rt->atom_hash = NULL; + rt->atom_count = 0; + rt->atom_size = 0; + rt->atom_free_index = 0; + if (JS_ResizeAtomHash(rt, 256)) /* there are at least 195 predefined atoms */ + return -1; + + p = js_atom_init; + for(i = 1; i < JS_ATOM_END; i++) { + if (i == JS_ATOM_Private_brand) + atom_type = JS_ATOM_TYPE_PRIVATE; + else if (i >= JS_ATOM_Symbol_toPrimitive) + atom_type = JS_ATOM_TYPE_SYMBOL; + else + atom_type = JS_ATOM_TYPE_STRING; + len = strlen(p); + if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL) + return -1; + p = p + len + 1; + } + return 0; +} + +JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v) +{ + JSAtomStruct *p; + + if (!__JS_AtomIsConst(v)) { + p = rt->atom_array[v]; + p->header.ref_count++; + } + return v; +} + +JSAtom JS_DupAtom(JSContext *ctx, JSAtom v) +{ + JSRuntime *rt; + JSAtomStruct *p; + + if (!__JS_AtomIsConst(v)) { + rt = ctx->rt; + p = rt->atom_array[v]; + p->header.ref_count++; + } + return v; +} + +static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v) +{ + JSRuntime *rt; + JSAtomStruct *p; + + rt = ctx->rt; + if (__JS_AtomIsTaggedInt(v)) + return JS_ATOM_KIND_STRING; + p = rt->atom_array[v]; + switch(p->atom_type) { + case JS_ATOM_TYPE_STRING: + return JS_ATOM_KIND_STRING; + case JS_ATOM_TYPE_GLOBAL_SYMBOL: + return JS_ATOM_KIND_SYMBOL; + case JS_ATOM_TYPE_SYMBOL: + switch(p->hash) { + case JS_ATOM_HASH_SYMBOL: + return JS_ATOM_KIND_SYMBOL; + case JS_ATOM_HASH_PRIVATE: + return JS_ATOM_KIND_PRIVATE; + default: + abort(); + } + default: + abort(); + } + return (JSAtomKindEnum){-1}; // pacify compiler +} + +static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p) +{ + uint32_t i = p->hash_next; /* atom_index */ + if (p->atom_type != JS_ATOM_TYPE_SYMBOL) { + JSAtomStruct *p1; + + i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)]; + p1 = rt->atom_array[i]; + while (p1 != p) { + assert(i != 0); + i = p1->hash_next; + p1 = rt->atom_array[i]; + } + } + return i; +} + +/* string case (internal). Return JS_ATOM_NULL if error. 'str' is + freed. */ +static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type) +{ + uint32_t h, h1, i; + JSAtomStruct *p; + int len; + + if (atom_type < JS_ATOM_TYPE_SYMBOL) { + /* str is not NULL */ + if (str->atom_type == atom_type) { + /* str is the atom, return its index */ + i = js_get_atom_index(rt, str); + /* reduce string refcount and increase atom's unless constant */ + if (__JS_AtomIsConst(i)) + str->header.ref_count--; + return i; + } + /* try and locate an already registered atom */ + len = str->len; + h = hash_string(str, atom_type); + h &= JS_ATOM_HASH_MASK; + h1 = h & (rt->atom_hash_size - 1); + i = rt->atom_hash[h1]; + while (i != 0) { + p = rt->atom_array[i]; + if (p->hash == h && + p->atom_type == atom_type && + p->len == len && + js_string_memcmp(p, str, len) == 0) { + if (!__JS_AtomIsConst(i)) + p->header.ref_count++; + goto done; + } + i = p->hash_next; + } + } else { + h1 = 0; /* avoid warning */ + if (atom_type == JS_ATOM_TYPE_SYMBOL) { + h = JS_ATOM_HASH_SYMBOL; + } else { + h = JS_ATOM_HASH_PRIVATE; + atom_type = JS_ATOM_TYPE_SYMBOL; + } + } + + if (rt->atom_free_index == 0) { + /* allow new atom entries */ + uint32_t new_size, start; + JSAtomStruct **new_array; + + /* alloc new with size progression 3/2: + 4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092 + preallocating space for predefined atoms (at least 195). + */ + new_size = max_int(211, rt->atom_size * 3 / 2); + if (new_size > JS_ATOM_MAX) + goto fail; + /* XXX: should use realloc2 to use slack space */ + new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size); + if (!new_array) + goto fail; + /* Note: the atom 0 is not used */ + start = rt->atom_size; + if (start == 0) { + /* JS_ATOM_NULL entry */ + p = js_mallocz_rt(rt, sizeof(JSAtomStruct)); + if (!p) { + js_free_rt(rt, new_array); + goto fail; + } + p->header.ref_count = 1; /* not refcounted */ + p->atom_type = JS_ATOM_TYPE_SYMBOL; +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + list_add_tail(&p->link, &rt->string_list); +#endif + new_array[0] = p; + rt->atom_count++; + start = 1; + } + rt->atom_size = new_size; + rt->atom_array = new_array; + rt->atom_free_index = start; + for(i = start; i < new_size; i++) { + uint32_t next; + if (i == (new_size - 1)) + next = 0; + else + next = i + 1; + rt->atom_array[i] = atom_set_free(next); + } + } + + if (str) { + if (str->atom_type == 0) { + p = str; + p->atom_type = atom_type; + } else { + p = js_malloc_rt(rt, sizeof(JSString) + + (str->len << str->is_wide_char) + + 1 - str->is_wide_char); + if (unlikely(!p)) + goto fail; + p->header.ref_count = 1; + p->is_wide_char = str->is_wide_char; + p->len = str->len; + p->kind = JS_STRING_KIND_NORMAL; +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + list_add_tail(&p->link, &rt->string_list); +#endif + memcpy(str8(p), str8(str), (str->len << str->is_wide_char) + + 1 - str->is_wide_char); + js_free_string(rt, str); + } + } else { + p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */ + if (!p) + return JS_ATOM_NULL; + p->header.ref_count = 1; + p->is_wide_char = 1; /* Hack to represent NULL as a JSString */ + p->len = 0; + p->kind = JS_STRING_KIND_NORMAL; +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + list_add_tail(&p->link, &rt->string_list); +#endif + } + + /* use an already free entry */ + i = rt->atom_free_index; + rt->atom_free_index = atom_get_free(rt->atom_array[i]); + rt->atom_array[i] = p; + + p->hash = h; + p->hash_next = i; /* atom_index */ + p->atom_type = atom_type; + p->first_weak_ref = NULL; + + rt->atom_count++; + + if (atom_type != JS_ATOM_TYPE_SYMBOL) { + p->hash_next = rt->atom_hash[h1]; + rt->atom_hash[h1] = i; + if (unlikely(rt->atom_count >= rt->atom_count_resize)) + JS_ResizeAtomHash(rt, rt->atom_hash_size * 2); + } + + // JS_DumpAtoms(rt); + return i; + + fail: + i = JS_ATOM_NULL; + done: + if (str) + js_free_string(rt, str); + return i; +} + +// XXX: `str` must be pure ASCII. No UTF-8 encoded strings +// XXX: `str` must not be the string representation of a small integer +static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, + int atom_type) +{ + JSString *p; + p = js_alloc_string_rt(rt, len, 0); + if (!p) + return JS_ATOM_NULL; + memcpy(str8(p), str, len); + str8(p)[len] = '\0'; + return __JS_NewAtom(rt, p, atom_type); +} + +// XXX: `str` must be raw 8-bit contents. No UTF-8 encoded strings +static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len, + int atom_type) +{ + uint32_t h, h1, i; + JSAtomStruct *p; + + h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING); + h &= JS_ATOM_HASH_MASK; + h1 = h & (rt->atom_hash_size - 1); + i = rt->atom_hash[h1]; + while (i != 0) { + p = rt->atom_array[i]; + if (p->hash == h && + p->atom_type == JS_ATOM_TYPE_STRING && + p->len == len && + p->is_wide_char == 0 && + memcmp(str8(p), str, len) == 0) { + if (!__JS_AtomIsConst(i)) + p->header.ref_count++; + return i; + } + i = p->hash_next; + } + return JS_ATOM_NULL; +} + +static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p) +{ + uint32_t i = p->hash_next; /* atom_index */ + if (p->atom_type != JS_ATOM_TYPE_SYMBOL) { + JSAtomStruct *p0, *p1; + uint32_t h0; + + h0 = p->hash & (rt->atom_hash_size - 1); + i = rt->atom_hash[h0]; + p1 = rt->atom_array[i]; + if (p1 == p) { + rt->atom_hash[h0] = p1->hash_next; + } else { + for(;;) { + assert(i != 0); + p0 = p1; + i = p1->hash_next; + p1 = rt->atom_array[i]; + if (p1 == p) { + p0->hash_next = p1->hash_next; + break; + } + } + } + } + /* insert in free atom list */ + rt->atom_array[i] = atom_set_free(rt->atom_free_index); + rt->atom_free_index = i; + if (unlikely(p->first_weak_ref)) { + reset_weak_ref(rt, &p->first_weak_ref); + } + /* free the string structure */ +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + list_del(&p->link); +#endif + js_free_rt(rt, p); + rt->atom_count--; + assert(rt->atom_count >= 0); +} + +static void __JS_FreeAtom(JSRuntime *rt, uint32_t i) +{ + JSAtomStruct *p; + + p = rt->atom_array[i]; + if (--p->header.ref_count > 0) + return; + JS_FreeAtomStruct(rt, p); +} + +/* Warning: 'p' is freed */ +static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p) +{ + JSRuntime *rt = ctx->rt; + uint32_t n; + if (is_num_string(&n, p)) { + if (n <= JS_ATOM_MAX_INT) { + js_free_string(rt, p); + return __JS_AtomFromUInt32(n); + } + } + /* XXX: should generate an exception */ + return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING); +} + +/* `str` may be pure ASCII or UTF-8 encoded */ +JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len) +{ + JSValue val; + + if (len == 0 || !is_digit(*str)) { + // TODO(chqrlie): this does not work if `str` has UTF-8 encoded contents + // bug example: `({ "\u00c3\u00a9": 1 }).\u00e9` evaluates to `1`. + JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING); + if (atom) + return atom; + } + val = JS_NewStringLen(ctx, str, len); + if (JS_IsException(val)) + return JS_ATOM_NULL; + return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val)); +} + +/* `str` may be pure ASCII or UTF-8 encoded */ +JSAtom JS_NewAtom(JSContext *ctx, const char *str) +{ + return JS_NewAtomLen(ctx, str, strlen(str)); +} + +JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n) +{ + if (n <= JS_ATOM_MAX_INT) { + return __JS_AtomFromUInt32(n); + } else { + char buf[16]; + size_t len = u32toa(buf, n); + JSValue val = js_new_string8_len(ctx, buf, len); + if (JS_IsException(val)) + return JS_ATOM_NULL; + return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), + JS_ATOM_TYPE_STRING); + } +} + +static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n) +{ + if ((uint64_t)n <= JS_ATOM_MAX_INT) { + return __JS_AtomFromUInt32((uint32_t)n); + } else { + char buf[24]; + size_t len = i64toa(buf, n); + JSValue val = js_new_string8_len(ctx, buf, len); + if (JS_IsException(val)) + return JS_ATOM_NULL; + return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), + JS_ATOM_TYPE_STRING); + } +} + +/* 'p' is freed */ +static JSValue JS_NewSymbolInternal(JSContext *ctx, JSString *p, int atom_type) +{ + JSRuntime *rt = ctx->rt; + JSAtom atom; + atom = __JS_NewAtom(rt, p, atom_type); + if (atom == JS_ATOM_NULL) + return JS_ThrowOutOfMemory(ctx); + return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]); +} + +/* descr must be a non-numeric string atom */ +static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr, + int atom_type) +{ + JSRuntime *rt = ctx->rt; + JSString *p; + + assert(!__JS_AtomIsTaggedInt(descr)); + assert(descr < rt->atom_size); + p = rt->atom_array[descr]; + js_dup(JS_MKPTR(JS_TAG_STRING, p)); + return JS_NewSymbolInternal(ctx, p, atom_type); +} + +/* `description` may be pure ASCII or UTF-8 encoded */ +JSValue JS_NewSymbol(JSContext *ctx, const char *description, bool is_global) +{ + JSAtom atom = JS_NewAtom(ctx, description); + if (atom == JS_ATOM_NULL) + return JS_EXCEPTION; + return JS_NewSymbolFromAtom(ctx, atom, is_global ? JS_ATOM_TYPE_GLOBAL_SYMBOL : JS_ATOM_TYPE_SYMBOL); +} + +#define ATOM_GET_STR_BUF_SIZE 64 + +static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, + JSAtom atom) +{ + if (__JS_AtomIsTaggedInt(atom)) { + snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom)); + } else if (atom == JS_ATOM_NULL) { + snprintf(buf, buf_size, ""); + } else if (atom >= rt->atom_size) { + assert(atom < rt->atom_size); + snprintf(buf, buf_size, "", atom); + } else { + JSAtomStruct *p = rt->atom_array[atom]; + *buf = '\0'; + if (atom_is_free(p)) { + snprintf(buf, buf_size, "", atom); + } else if (p != NULL) { + JSString *str = p; + if (str->is_wide_char) { + /* encode surrogates correctly */ + utf8_encode_buf16(buf, buf_size, str16(str), str->len); + } else { + utf8_encode_buf8(buf, buf_size, str8(str), str->len); + } + } + } + return buf; +} + +static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom) +{ + return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom); +} + +static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, bool force_string) +{ + char buf[ATOM_GET_STR_BUF_SIZE]; + + if (__JS_AtomIsTaggedInt(atom)) { + size_t len = u32toa(buf, __JS_AtomToUInt32(atom)); + return js_new_string8_len(ctx, buf, len); + } else { + JSRuntime *rt = ctx->rt; + JSAtomStruct *p; + assert(atom < rt->atom_size); + p = rt->atom_array[atom]; + if (p->atom_type == JS_ATOM_TYPE_STRING) { + goto ret_string; + } else if (force_string) { + if (p->len == 0 && p->is_wide_char != 0) { + /* no description string */ + p = rt->atom_array[JS_ATOM_empty_string]; + } + ret_string: + return js_dup(JS_MKPTR(JS_TAG_STRING, p)); + } else { + return js_dup(JS_MKPTR(JS_TAG_SYMBOL, p)); + } + } +} + +JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom) +{ + return __JS_AtomToValue(ctx, atom, false); +} + +JSValue JS_AtomToString(JSContext *ctx, JSAtom atom) +{ + return __JS_AtomToValue(ctx, atom, true); +} + +/* return true if the atom is an array index (i.e. 0 <= index <= + 2^32-2 and return its value */ +static bool JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom) +{ + if (__JS_AtomIsTaggedInt(atom)) { + *pval = __JS_AtomToUInt32(atom); + return true; + } else { + JSRuntime *rt = ctx->rt; + JSAtomStruct *p; + uint32_t val; + + assert(atom < rt->atom_size); + p = rt->atom_array[atom]; + if (p->atom_type == JS_ATOM_TYPE_STRING && + is_num_string(&val, p) && val != -1) { + *pval = val; + return true; + } else { + *pval = 0; + return false; + } + } +} + +/* This test must be fast if atom is not a numeric index (e.g. a + method name). Return JS_UNDEFINED if not a numeric + index. JS_EXCEPTION can also be returned. */ +static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom) +{ + JSRuntime *rt = ctx->rt; + JSAtomStruct *p1; + JSString *p; + int c, len, ret; + JSValue num, str; + + if (__JS_AtomIsTaggedInt(atom)) + return js_int32(__JS_AtomToUInt32(atom)); + assert(atom < rt->atom_size); + p1 = rt->atom_array[atom]; + if (p1->atom_type != JS_ATOM_TYPE_STRING) + return JS_UNDEFINED; + p = p1; + len = p->len; + if (p->is_wide_char) { + const uint16_t *r = str16(p), *r_end = str16(p) + len; + if (r >= r_end) + return JS_UNDEFINED; + c = *r; + if (c == '-') { + if (r >= r_end) + return JS_UNDEFINED; + r++; + c = *r; + /* -0 case is specific */ + if (c == '0' && len == 2) + goto minus_zero; + } + /* XXX: should test NaN, but the tests do not check it */ + if (!is_num(c)) { + /* XXX: String should be normalized, therefore 8-bit only */ + const uint16_t nfinity16[7] = { 'n', 'f', 'i', 'n', 'i', 't', 'y' }; + if (!(c =='I' && (r_end - r) == 8 && + !memcmp(r + 1, nfinity16, sizeof(nfinity16)))) + return JS_UNDEFINED; + } + } else { + const uint8_t *r = str8(p), *r_end = str8(p) + len; + if (r >= r_end) + return JS_UNDEFINED; + c = *r; + if (c == '-') { + if (r >= r_end) + return JS_UNDEFINED; + r++; + c = *r; + /* -0 case is specific */ + if (c == '0' && len == 2) { + minus_zero: + return js_float64(-0.0); + } + } + if (!is_num(c)) { + if (!(c =='I' && (r_end - r) == 8 && + !memcmp(r + 1, "nfinity", 7))) + return JS_UNDEFINED; + } + } + /* this is ECMA CanonicalNumericIndexString primitive */ + num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p)); + if (JS_IsException(num)) + return num; + str = JS_ToString(ctx, num); + if (JS_IsException(str)) { + JS_FreeValue(ctx, num); + return str; + } + ret = js_string_eq(p, JS_VALUE_GET_STRING(str)); + JS_FreeValue(ctx, str); + if (ret) { + return num; + } else { + JS_FreeValue(ctx, num); + return JS_UNDEFINED; + } +} + +/* return -1 if exception or true/false */ +static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom) +{ + JSValue num; + num = JS_AtomIsNumericIndex1(ctx, atom); + if (likely(JS_IsUndefined(num))) + return false; + if (JS_IsException(num)) + return -1; + JS_FreeValue(ctx, num); + return true; +} + +void JS_FreeAtom(JSContext *ctx, JSAtom v) +{ + if (!__JS_AtomIsConst(v)) + __JS_FreeAtom(ctx->rt, v); +} + +void JS_FreeAtomRT(JSRuntime *rt, JSAtom v) +{ + if (!__JS_AtomIsConst(v)) + __JS_FreeAtom(rt, v); +} + +/* return true if 'v' is a symbol with a string description */ +static bool JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v) +{ + JSRuntime *rt; + JSAtomStruct *p; + + rt = ctx->rt; + if (__JS_AtomIsTaggedInt(v)) + return false; + p = rt->atom_array[v]; + return (((p->atom_type == JS_ATOM_TYPE_SYMBOL && + p->hash == JS_ATOM_HASH_SYMBOL) || + p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) && + !(p->len == 0 && p->is_wide_char != 0)); +} + +static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom) +{ + char buf[ATOM_GET_STR_BUF_SIZE]; + const char *p; + int i; + + /* XXX: should handle embedded null characters */ + /* XXX: should move encoding code to JS_AtomGetStr */ + p = JS_AtomGetStr(ctx, buf, sizeof(buf), atom); + for (i = 0; p[i]; i++) { + int c = (unsigned char)p[i]; + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0))) + break; + } + if (i > 0 && p[i] == '\0') { + printf("%s", p); + } else { + putchar('"'); + printf("%.*s", i, p); + for (; p[i]; i++) { + int c = (unsigned char)p[i]; + if (c == '\"' || c == '\\') { + putchar('\\'); + putchar(c); + } else if (c >= ' ' && c <= 126) { + putchar(c); + } else if (c == '\n') { + putchar('\\'); + putchar('n'); + } else { + printf("\\u%04x", c); + } + } + putchar('\"'); + } +} + +/* free with JS_FreeCString() */ +const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom) +{ + JSValue str; + const char *cstr; + + str = JS_AtomToString(ctx, atom); + if (JS_IsException(str)) { + if (plen) + *plen = 0; + return NULL; + } + cstr = JS_ToCStringLen(ctx, plen, str); + JS_FreeValue(ctx, str); + return cstr; +} + +#ifndef QJS_DISABLE_PARSER + +/* return a string atom containing name concatenated with str1 */ +/* `str1` may be pure ASCII or UTF-8 encoded */ +// TODO(chqrlie): use string concatenation instead of UTF-8 conversion +static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1) +{ + JSValue str; + JSAtom atom; + const char *cstr; + char *cstr2; + size_t len, len1; + + str = JS_AtomToString(ctx, name); + if (JS_IsException(str)) + return JS_ATOM_NULL; + cstr = JS_ToCStringLen(ctx, &len, str); + if (!cstr) + goto fail; + len1 = strlen(str1); + cstr2 = js_malloc(ctx, len + len1 + 1); + if (!cstr2) + goto fail; + memcpy(cstr2, cstr, len); + memcpy(cstr2 + len, str1, len1); + cstr2[len + len1] = '\0'; + atom = JS_NewAtomLen(ctx, cstr2, len + len1); + js_free(ctx, cstr2); + JS_FreeCString(ctx, cstr); + JS_FreeValue(ctx, str); + return atom; + fail: + JS_FreeCString(ctx, cstr); + JS_FreeValue(ctx, str); + return JS_ATOM_NULL; +} + +static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n) +{ + char buf[16]; + size_t len; + + len = u32toa(buf, n); + buf[len] = '\0'; + return js_atom_concat_str(ctx, name, buf); +} + +#endif // QJS_DISABLE_PARSER + +static inline bool JS_IsEmptyString(JSValueConst v) +{ + return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0; +} + +/* JSClass support */ + +/* a new class ID is allocated if *pclass_id == 0, otherwise *pclass_id is left unchanged */ +JSClassID JS_NewClassID(JSRuntime *rt, JSClassID *pclass_id) +{ + JSClassID class_id = *pclass_id; + if (class_id == 0) { + class_id = rt->js_class_id_alloc++; + *pclass_id = class_id; + } + return class_id; +} + +JSClassID JS_GetClassID(JSValueConst v) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) + return JS_INVALID_CLASS_ID; + p = JS_VALUE_GET_OBJ(v); + return p->class_id; +} + +bool JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id) +{ + return (class_id < rt->class_count && + rt->class_array[class_id].class_id != 0); +} + +JSAtom JS_GetClassName(JSRuntime *rt, JSClassID class_id) +{ + if (JS_IsRegisteredClass(rt, class_id)) { + return JS_DupAtomRT(rt, rt->class_array[class_id].class_id); + } else { + return JS_ATOM_NULL; + } +} + +/* create a new object internal class. Return -1 if error, 0 if + OK. The finalizer can be NULL if none is needed. */ +static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, + const JSClassDef *class_def, JSAtom name) +{ + int new_size, i; + JSClass *cl, *new_class_array; + struct list_head *el; + + if (class_id >= (1 << 16)) + return -1; + if (class_id < rt->class_count && + rt->class_array[class_id].class_id != 0) + return -1; + + if (class_id >= rt->class_count) { + new_size = max_int(JS_CLASS_INIT_COUNT, + max_int(class_id + 1, rt->class_count * 3 / 2)); + + /* reallocate the context class prototype array, if any */ + list_for_each(el, &rt->context_list) { + JSContext *ctx = list_entry(el, JSContext, link); + JSValue *new_tab; + new_tab = js_realloc_rt(rt, ctx->class_proto, + sizeof(ctx->class_proto[0]) * new_size); + if (!new_tab) + return -1; + for(i = rt->class_count; i < new_size; i++) + new_tab[i] = JS_NULL; + ctx->class_proto = new_tab; + } + /* reallocate the class array */ + new_class_array = js_realloc_rt(rt, rt->class_array, + sizeof(JSClass) * new_size); + if (!new_class_array) + return -1; + memset(new_class_array + rt->class_count, 0, + (new_size - rt->class_count) * sizeof(JSClass)); + rt->class_array = new_class_array; + rt->class_count = new_size; + } + cl = &rt->class_array[class_id]; + cl->class_id = class_id; + cl->class_name = JS_DupAtomRT(rt, name); + cl->finalizer = class_def->finalizer; + cl->gc_mark = class_def->gc_mark; + cl->call = class_def->call; + cl->exotic = class_def->exotic; + return 0; +} + +int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def) +{ + int ret, len; + JSAtom name; + + // XXX: class_def->class_name must be raw 8-bit contents. No UTF-8 encoded strings + len = strlen(class_def->class_name); + name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING); + if (name == JS_ATOM_NULL) { + name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING); + if (name == JS_ATOM_NULL) + return -1; + } + ret = JS_NewClass1(rt, class_id, class_def, name); + JS_FreeAtomRT(rt, name); + return ret; +} + +static inline JSValue js_empty_string(JSRuntime *rt) +{ + JSAtomStruct *p = rt->atom_array[JS_ATOM_empty_string]; + return js_dup(JS_MKPTR(JS_TAG_STRING, p)); +} + +// XXX: `buf` contains raw 8-bit data, no UTF-8 decoding is performed +// XXX: no special case for len == 0 +static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len) +{ + JSString *str; + str = js_alloc_string(ctx, len, 0); + if (!str) + return JS_EXCEPTION; + memcpy(str8(str), buf, len); + str8(str)[len] = '\0'; + return JS_MKPTR(JS_TAG_STRING, str); +} + +// XXX: `buf` contains raw 8-bit data, no UTF-8 decoding is performed +// XXX: no special case for the empty string +static inline JSValue js_new_string8(JSContext *ctx, const char *str) +{ + return js_new_string8_len(ctx, str, strlen(str)); +} + +static JSValue js_new_string16_len(JSContext *ctx, const uint16_t *buf, int len) +{ + JSString *str; + str = js_alloc_string(ctx, len, 1); + if (!str) + return JS_EXCEPTION; + memcpy(str16(str), buf, len * 2); + return JS_MKPTR(JS_TAG_STRING, str); +} + +static JSValue js_new_string_char(JSContext *ctx, uint16_t c) +{ + if (c < 0x100) { + char ch8 = c; + return js_new_string8_len(ctx, &ch8, 1); + } else { + uint16_t ch16 = c; + return js_new_string16_len(ctx, &ch16, 1); + } +} + +static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end) +{ + JSStringSlice *slice; + JSString *q; + int len; + + len = end - start; + if (start == 0 && end == p->len) { + return js_dup(JS_MKPTR(JS_TAG_STRING, p)); + } + if (len <= 0) { + return js_empty_string(ctx->rt); + } + if (len > (JS_STRING_SLICE_LEN_MAX >> p->is_wide_char)) { + if (p->kind == JS_STRING_KIND_SLICE) { + slice = (void *)&p[1]; + p = slice->parent; + start += slice->start >> p->is_wide_char; // bytes -> chars + } + // allocate as 16 bit wide string to avoid wastage; + // js_alloc_string allocates 1 byte extra for 8 bit strings; + q = js_alloc_string(ctx, sizeof(*slice)/2, /*is_wide_char*/true); + if (!q) + return JS_EXCEPTION; + q->is_wide_char = p->is_wide_char; + q->kind = JS_STRING_KIND_SLICE; + q->len = len; + slice = (void *)&q[1]; + slice->parent = p; + slice->start = start << p->is_wide_char; // chars -> bytes + p->header.ref_count++; + return JS_MKPTR(JS_TAG_STRING, q); + } + if (p->is_wide_char) { + JSString *str; + int i; + uint16_t c = 0; + for (i = start; i < end; i++) { + c |= str16(p)[i]; + } + if (c > 0xFF) + return js_new_string16_len(ctx, str16(p) + start, len); + + str = js_alloc_string(ctx, len, 0); + if (!str) + return JS_EXCEPTION; + for (i = 0; i < len; i++) { + str8(str)[i] = str16(p)[start + i]; + } + str8(str)[len] = '\0'; + return JS_MKPTR(JS_TAG_STRING, str); + } else { + return js_new_string8_len(ctx, (const char *)(str8(p) + start), len); + } +} + +typedef struct StringBuffer { + JSContext *ctx; + JSString *str; + int len; + int size; + int is_wide_char; + int error_status; +} StringBuffer; + +/* It is valid to call string_buffer_end() and all string_buffer functions even + if string_buffer_init() or another string_buffer function returns an error. + If the error_status is set, string_buffer_end() returns JS_EXCEPTION. + */ +static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size, + int is_wide) +{ + s->ctx = ctx; + s->size = size; + s->len = 0; + s->is_wide_char = is_wide; + s->error_status = 0; + s->str = js_alloc_string(ctx, size, is_wide); + if (unlikely(!s->str)) { + s->size = 0; + return s->error_status = -1; + } +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + /* the StringBuffer may reallocate the JSString, only link it at the end */ + list_del(&s->str->link); +#endif + return 0; +} + +static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size) +{ + return string_buffer_init2(ctx, s, size, 0); +} + +static void string_buffer_free(StringBuffer *s) +{ + js_free(s->ctx, s->str); + s->str = NULL; +} + +static int string_buffer_set_error(StringBuffer *s) +{ + js_free(s->ctx, s->str); + s->str = NULL; + s->size = 0; + s->len = 0; + return s->error_status = -1; +} + +static no_inline int string_buffer_widen(StringBuffer *s, int size) +{ + JSString *str; + size_t slack; + int i; + + if (s->error_status) + return -1; + + str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack); + if (!str) + return string_buffer_set_error(s); + size += slack >> 1; + for(i = s->len; i-- > 0;) { + str16(str)[i] = str8(str)[i]; + } + s->is_wide_char = 1; + s->size = size; + s->str = str; + return 0; +} + +static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c) +{ + JSString *new_str; + int new_size; + size_t new_size_bytes, slack; + + if (s->error_status) + return -1; + + if (new_len > JS_STRING_LEN_MAX) { + JS_ThrowRangeError(s->ctx, "invalid string length"); + return string_buffer_set_error(s); + } + new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX); + if (!s->is_wide_char && c >= 0x100) { + return string_buffer_widen(s, new_size); + } + new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char; + new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack); + if (!new_str) + return string_buffer_set_error(s); + new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX); + s->size = new_size; + s->str = new_str; + return 0; +} + +static no_inline int string_buffer_putc_slow(StringBuffer *s, uint32_t c) +{ + if (unlikely(s->len >= s->size)) { + if (string_buffer_realloc(s, s->len + 1, c)) + return -1; + } + if (s->is_wide_char) { + str16(s->str)[s->len++] = c; + } else if (c < 0x100) { + str8(s->str)[s->len++] = c; + } else { + if (string_buffer_widen(s, s->size)) + return -1; + str16(s->str)[s->len++] = c; + } + return 0; +} + +/* 0 <= c <= 0xff */ +static int string_buffer_putc8(StringBuffer *s, uint32_t c) +{ + if (unlikely(s->len >= s->size)) { + if (string_buffer_realloc(s, s->len + 1, c)) + return -1; + } + if (s->is_wide_char) { + str16(s->str)[s->len++] = c; + } else { + str8(s->str)[s->len++] = c; + } + return 0; +} + +/* 0 <= c <= 0xffff */ +static int string_buffer_putc16(StringBuffer *s, uint32_t c) +{ + if (likely(s->len < s->size)) { + if (s->is_wide_char) { + str16(s->str)[s->len++] = c; + return 0; + } else if (c < 0x100) { + str8(s->str)[s->len++] = c; + return 0; + } + } + return string_buffer_putc_slow(s, c); +} + +/* 0 <= c <= 0x10ffff */ +static int string_buffer_putc(StringBuffer *s, uint32_t c) +{ + if (unlikely(c >= 0x10000)) { + /* surrogate pair */ + if (string_buffer_putc16(s, get_hi_surrogate(c))) + return -1; + c = get_lo_surrogate(c); + } + return string_buffer_putc16(s, c); +} + +static int string_getc(JSString *p, int *pidx) +{ + int idx, c, c1; + idx = *pidx; + if (p->is_wide_char) { + c = str16(p)[idx++]; + if (is_hi_surrogate(c) && idx < p->len) { + c1 = str16(p)[idx]; + if (is_lo_surrogate(c1)) { + c = from_surrogate(c, c1); + idx++; + } + } + } else { + c = str8(p)[idx++]; + } + *pidx = idx; + return c; +} + +static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len) +{ + int i; + + if (s->len + len > s->size) { + if (string_buffer_realloc(s, s->len + len, 0)) + return -1; + } + if (s->is_wide_char) { + for (i = 0; i < len; i++) { + str16(s->str)[s->len + i] = p[i]; + } + s->len += len; + } else { + memcpy(&str8(s->str)[s->len], p, len); + s->len += len; + } + return 0; +} + +static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len) +{ + int c = 0, i; + + for (i = 0; i < len; i++) { + c |= p[i]; + } + if (s->len + len > s->size) { + if (string_buffer_realloc(s, s->len + len, c)) + return -1; + } else if (!s->is_wide_char && c >= 0x100) { + if (string_buffer_widen(s, s->size)) + return -1; + } + if (s->is_wide_char) { + memcpy(&str16(s->str)[s->len], p, len << 1); + s->len += len; + } else { + for (i = 0; i < len; i++) { + str8(s->str)[s->len + i] = p[i]; + } + s->len += len; + } + return 0; +} + +/* appending an ASCII string */ +static int string_buffer_puts8(StringBuffer *s, const char *str) +{ + return string_buffer_write8(s, (const uint8_t *)str, strlen(str)); +} + +static int string_buffer_concat(StringBuffer *s, JSString *p, + uint32_t from, uint32_t to) +{ + if (to <= from) + return 0; + if (p->is_wide_char) + return string_buffer_write16(s, str16(p) + from, to - from); + else + return string_buffer_write8(s, str8(p) + from, to - from); +} + +static int string_buffer_concat_value(StringBuffer *s, JSValueConst v) +{ + JSString *p; + JSValue v1; + int res; + + if (s->error_status) { + /* prevent exception overload */ + return -1; + } + if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) { + v1 = JS_ToString(s->ctx, v); + if (JS_IsException(v1)) + return string_buffer_set_error(s); + p = JS_VALUE_GET_STRING(v1); + res = string_buffer_concat(s, p, 0, p->len); + JS_FreeValue(s->ctx, v1); + return res; + } + p = JS_VALUE_GET_STRING(v); + return string_buffer_concat(s, p, 0, p->len); +} + +static int string_buffer_concat_value_free(StringBuffer *s, JSValue v) +{ + JSString *p; + int res; + + if (s->error_status) { + /* prevent exception overload */ + JS_FreeValue(s->ctx, v); + return -1; + } + if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) { + v = JS_ToStringFree(s->ctx, v); + if (JS_IsException(v)) + return string_buffer_set_error(s); + } + p = JS_VALUE_GET_STRING(v); + res = string_buffer_concat(s, p, 0, p->len); + JS_FreeValue(s->ctx, v); + return res; +} + +static int string_buffer_fill(StringBuffer *s, int c, int count) +{ + /* XXX: optimize */ + if (s->len + count > s->size) { + if (string_buffer_realloc(s, s->len + count, c)) + return -1; + } + while (count-- > 0) { + if (string_buffer_putc16(s, c)) + return -1; + } + return 0; +} + +static JSValue string_buffer_end(StringBuffer *s) +{ + JSString *str; + str = s->str; + if (s->error_status) + return JS_EXCEPTION; + if (s->len == 0) { + js_free(s->ctx, str); + s->str = NULL; + return js_empty_string(s->ctx->rt); + } + if (s->len < s->size) { + /* smaller size so js_realloc should not fail, but OK if it does */ + /* XXX: should add some slack to avoid unnecessary calls */ + /* XXX: might need to use malloc+free to ensure smaller size */ + str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) + + (s->len << s->is_wide_char) + 1 - s->is_wide_char); + if (str == NULL) + str = s->str; + s->str = str; + } + if (!s->is_wide_char) + str8(str)[s->len] = 0; +#ifdef ENABLE_DUMPS // JS_DUMP_LEAKS + list_add_tail(&str->link, &s->ctx->rt->string_list); +#endif + str->is_wide_char = s->is_wide_char; + str->len = s->len; + s->str = NULL; + return JS_MKPTR(JS_TAG_STRING, str); +} + +/* create a string from a UTF-8 buffer */ +JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len) +{ + JSString *str; + size_t len; + int kind; + + if (buf_len <= 0) { + return js_empty_string(ctx->rt); + } + /* Compute string kind and length: 7-bit, 8-bit, 16-bit, 16-bit UTF-16 */ + kind = utf8_scan(buf, buf_len, &len); + if (len > JS_STRING_LEN_MAX) + return JS_ThrowRangeError(ctx, "invalid string length"); + + switch (kind) { + case UTF8_PLAIN_ASCII: + str = js_alloc_string(ctx, len, 0); + if (!str) + return JS_EXCEPTION; + memcpy(str8(str), buf, len); + str8(str)[len] = '\0'; + break; + case UTF8_NON_ASCII: + /* buf contains non-ASCII code-points, but limited to 8-bit values */ + str = js_alloc_string(ctx, len, 0); + if (!str) + return JS_EXCEPTION; + utf8_decode_buf8(str8(str), len + 1, buf, buf_len); + break; + default: + // This causes a potential problem in JS_ThrowError if message is invalid + //if (kind & UTF8_HAS_ERRORS) + // return JS_ThrowRangeError(ctx, "invalid UTF-8 sequence"); + str = js_alloc_string(ctx, len, 1); + if (!str) + return JS_EXCEPTION; + utf8_decode_buf16(str16(str), len, buf, buf_len); + break; + } + return JS_MKPTR(JS_TAG_STRING, str); +} + +JSValue JS_NewTwoByteString(JSContext *ctx, const uint16_t *buf, size_t len) +{ + JSString *str; + + if (!len) + return js_empty_string(ctx->rt); + str = js_alloc_string(ctx, len, 1); + if (!str) + return JS_EXCEPTION; + memcpy(str16(str), buf, len * sizeof(*buf)); + return JS_MKPTR(JS_TAG_STRING, str); +} + +static JSValue JS_ConcatString3(JSContext *ctx, const char *str1, + JSValue str2, const char *str3) +{ + StringBuffer b_s, *b = &b_s; + int len1, len3; + JSString *p; + + if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) { + str2 = JS_ToStringFree(ctx, str2); + if (JS_IsException(str2)) + goto fail; + } + p = JS_VALUE_GET_STRING(str2); + len1 = strlen(str1); + len3 = strlen(str3); + + if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char)) + goto fail; + + string_buffer_write8(b, (const uint8_t *)str1, len1); + string_buffer_concat(b, p, 0, p->len); + string_buffer_write8(b, (const uint8_t *)str3, len3); + + JS_FreeValue(ctx, str2); + return string_buffer_end(b); + + fail: + JS_FreeValue(ctx, str2); + return JS_EXCEPTION; +} + +/* `str` may be pure ASCII or UTF-8 encoded */ +JSValue JS_NewAtomString(JSContext *ctx, const char *str) +{ + JSAtom atom = JS_NewAtom(ctx, str); + if (atom == JS_ATOM_NULL) + return JS_EXCEPTION; + JSValue val = JS_AtomToString(ctx, atom); + JS_FreeAtom(ctx, atom); + return val; +} + +/* return (NULL, 0) if exception. */ +/* return pointer into a JSString with a live ref_count */ +/* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */ +const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, + bool cesu8) +{ + JSValue val; + JSString *str, *str_new; + int pos, len, c, c1; + JSObject *p; + uint8_t *q; + + if (JS_VALUE_GET_TAG(val1) == JS_TAG_STRING) { + val = js_dup(val1); + goto go; + } + + val = JS_ToString(ctx, val1); + if (!JS_IsException(val)) + goto go; + + // Stringification can fail when there is an exception pending, + // e.g. a stack overflow InternalError. Special-case exception + // objects to make debugging easier, look up the .message property + // and stringify that. + if (JS_VALUE_GET_TAG(val1) != JS_TAG_OBJECT) + goto fail; + + p = JS_VALUE_GET_OBJ(val1); + if (p->class_id != JS_CLASS_ERROR) + goto fail; + + val = JS_GetProperty(ctx, val1, JS_ATOM_message); + if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) { + JS_FreeValue(ctx, val); + goto fail; + } + +go: + str = JS_VALUE_GET_STRING(val); + len = str->len; + if (!str->is_wide_char) { + const uint8_t *src = str8(str); + int count; + + /* count the number of non-ASCII characters */ + /* Scanning the whole string is required for ASCII strings, + and computing the number of non-ASCII bytes is less expensive + than testing each byte, hence this method is faster for ASCII + strings, which is the most common case. + */ + count = 0; + for (pos = 0; pos < len; pos++) { + count += src[pos] >> 7; + } + if (count == 0 && str->kind == JS_STRING_KIND_NORMAL) { + if (plen) + *plen = len; + return (const char *)src; + } + str_new = js_alloc_string(ctx, len + count, 0); + if (!str_new) + goto fail; + q = str8(str_new); + for (pos = 0; pos < len; pos++) { + c = src[pos]; + if (c < 0x80) { + *q++ = c; + } else { + *q++ = (c >> 6) | 0xc0; + *q++ = (c & 0x3f) | 0x80; + } + } + } else { + const uint16_t *src = str16(str); + /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may + produce 4 bytes but use 2 code points. + */ + str_new = js_alloc_string(ctx, len * 3, 0); + if (!str_new) + goto fail; + q = str8(str_new); + pos = 0; + while (pos < len) { + c = src[pos++]; + if (c < 0x80) { + *q++ = c; + } else { + if (is_hi_surrogate(c)) { + if (pos < len && !cesu8) { + c1 = src[pos]; + if (is_lo_surrogate(c1)) { + pos++; + c = from_surrogate(c, c1); + } else { + /* Keep unmatched surrogate code points */ + /* c = 0xfffd; */ /* error */ + } + } else { + /* Keep unmatched surrogate code points */ + /* c = 0xfffd; */ /* error */ + } + } + q += utf8_encode(q, c); + } + } + } + + *q = '\0'; + str_new->len = q - str8(str_new); + JS_FreeValue(ctx, val); + if (plen) + *plen = str_new->len; + return (const char *)str8(str_new); + fail: + if (plen) + *plen = 0; + return NULL; +} + +void JS_FreeCString(JSContext *ctx, const char *ptr) +{ + if (!ptr) + return; + /* purposely removing constness */ + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, (JSString *)ptr - 1)); +} + +void JS_FreeCStringRT(JSRuntime *rt, const char *ptr) +{ + if (!ptr) + return; + /* purposely removing constness */ + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, (JSString *)ptr - 1)); +} + +static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len) +{ + int c, i; + for(i = 0; i < len; i++) { + c = src1[i] - src2[i]; + if (c != 0) + return c; + } + return 0; +} + +static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len) +{ + int c, i; + for(i = 0; i < len; i++) { + c = src1[i] - src2[i]; + if (c != 0) + return c; + } + return 0; +} + +static int js_string_memcmp(JSString *p1, JSString *p2, int len) +{ + int res; + + if (likely(!p1->is_wide_char)) { + if (likely(!p2->is_wide_char)) + res = memcmp(str8(p1), str8(p2), len); + else + res = -memcmp16_8(str16(p2), str8(p1), len); + } else { + if (!p2->is_wide_char) + res = memcmp16_8(str16(p1), str8(p2), len); + else + res = memcmp16(str16(p1), str16(p2), len); + } + return res; +} + +static bool js_string_eq(JSString *p1, JSString *p2) { + if (p1->len != p2->len) + return false; + return js_string_memcmp(p1, p2, p1->len) == 0; +} + +/* return < 0, 0 or > 0 */ +static int js_string_compare(JSString *p1, JSString *p2) +{ + int res, len; + len = min_int(p1->len, p2->len); + res = js_string_memcmp(p1, p2, len); + if (res == 0) + res = compare_u32(p1->len, p2->len); + return res; +} + +static void copy_str16(uint16_t *dst, JSString *p, int offset, int len) +{ + if (p->is_wide_char) { + memcpy(dst, str16(p) + offset, len * 2); + } else { + const uint8_t *src1 = str8(p) + offset; + int i; + + for(i = 0; i < len; i++) + dst[i] = src1[i]; + } +} + +static JSValue JS_ConcatString1(JSContext *ctx, JSString *p1, JSString *p2) +{ + JSString *p; + uint32_t len; + int is_wide_char; + + len = p1->len + p2->len; + if (len > JS_STRING_LEN_MAX) + return JS_ThrowRangeError(ctx, "invalid string length"); + is_wide_char = p1->is_wide_char | p2->is_wide_char; + p = js_alloc_string(ctx, len, is_wide_char); + if (!p) + return JS_EXCEPTION; + if (!is_wide_char) { + memcpy(str8(p), str8(p1), p1->len); + memcpy(str8(p) + p1->len, str8(p2), p2->len); + str8(p)[len] = '\0'; + } else { + copy_str16(str16(p), p1, 0, p1->len); + copy_str16(str16(p) + p1->len, p2, 0, p2->len); + } + return JS_MKPTR(JS_TAG_STRING, p); +} + +/* op1 and op2 are converted to strings. For convience, op1 or op2 = + JS_EXCEPTION are accepted and return JS_EXCEPTION. */ +static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2) +{ + JSValue ret; + JSString *p1, *p2; + + if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) { + op1 = JS_ToStringFree(ctx, op1); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + return JS_EXCEPTION; + } + } + if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING)) { + op2 = JS_ToStringFree(ctx, op2); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + return JS_EXCEPTION; + } + } + p1 = JS_VALUE_GET_STRING(op1); + p2 = JS_VALUE_GET_STRING(op2); + + /* XXX: could also check if p1 is empty */ + if (p2->len == 0) { + goto ret_op1; + } + if (p1->header.ref_count == 1 && p1->is_wide_char == p2->is_wide_char + && js_malloc_usable_size(ctx, p1) >= sizeof(*p1) + ((p1->len + p2->len) << p2->is_wide_char) + 1 - p1->is_wide_char) { + /* Concatenate in place in available space at the end of p1 */ + if (p1->is_wide_char) { + memcpy(str16(p1) + p1->len, str16(p2), p2->len << 1); + p1->len += p2->len; + } else { + memcpy(str8(p1) + p1->len, str8(p2), p2->len); + p1->len += p2->len; + str8(p1)[p1->len] = '\0'; + } + ret_op1: + JS_FreeValue(ctx, op2); + return op1; + } + ret = JS_ConcatString1(ctx, p1, p2); + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + return ret; +} + +/* Shape support */ + +static inline size_t get_shape_size(size_t hash_size, size_t prop_size) +{ + return hash_size * sizeof(uint32_t) + sizeof(JSShape) + + prop_size * sizeof(JSShapeProperty); +} + +static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size) +{ + return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size); +} + +static inline uint32_t *prop_hash_end(JSShape *sh) +{ + return (uint32_t *)sh; +} + +static inline void *get_alloc_from_shape(JSShape *sh) +{ + return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1); +} + +static inline JSShapeProperty *get_shape_prop(JSShape *sh) +{ + return sh->prop; +} + +static int init_shape_hash(JSRuntime *rt) +{ + rt->shape_hash_bits = 6; /* 64 shapes */ + rt->shape_hash_size = 1 << rt->shape_hash_bits; + rt->shape_hash_count = 0; + rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) * + rt->shape_hash_size); + if (!rt->shape_hash) + return -1; + return 0; +} + +/* same magic hash multiplier as the Linux kernel */ +static uint32_t shape_hash(uint32_t h, uint32_t val) +{ + return (h + val) * 0x9e370001; +} + +/* truncate the shape hash to 'hash_bits' bits */ +static uint32_t get_shape_hash(uint32_t h, int hash_bits) +{ + return h >> (32 - hash_bits); +} + +static uint32_t shape_initial_hash(JSObject *proto) +{ + uint32_t h; + h = shape_hash(1, (uintptr_t)proto); + if (sizeof(proto) > 4) + h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32); + return h; +} + +static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits) +{ + int new_shape_hash_size, i; + uint32_t h; + JSShape **new_shape_hash, *sh, *sh_next; + + new_shape_hash_size = 1 << new_shape_hash_bits; + new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) * + new_shape_hash_size); + if (!new_shape_hash) + return -1; + for(i = 0; i < rt->shape_hash_size; i++) { + for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) { + sh_next = sh->shape_hash_next; + h = get_shape_hash(sh->hash, new_shape_hash_bits); + sh->shape_hash_next = new_shape_hash[h]; + new_shape_hash[h] = sh; + } + } + js_free_rt(rt, rt->shape_hash); + rt->shape_hash_bits = new_shape_hash_bits; + rt->shape_hash_size = new_shape_hash_size; + rt->shape_hash = new_shape_hash; + return 0; +} + +static void js_shape_hash_link(JSRuntime *rt, JSShape *sh) +{ + uint32_t h; + h = get_shape_hash(sh->hash, rt->shape_hash_bits); + sh->shape_hash_next = rt->shape_hash[h]; + rt->shape_hash[h] = sh; + rt->shape_hash_count++; +} + +static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh) +{ + uint32_t h; + JSShape **psh; + + h = get_shape_hash(sh->hash, rt->shape_hash_bits); + psh = &rt->shape_hash[h]; + while (*psh != sh) + psh = &(*psh)->shape_hash_next; + *psh = sh->shape_hash_next; + rt->shape_hash_count--; +} + +/* create a new empty shape with prototype 'proto' */ +static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, + int hash_size, int prop_size) +{ + JSRuntime *rt = ctx->rt; + void *sh_alloc; + JSShape *sh; + + /* resize the shape hash table if necessary */ + if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) { + resize_shape_hash(rt, rt->shape_hash_bits + 1); + } + + sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size)); + if (!sh_alloc) + return NULL; + sh = get_shape_from_alloc(sh_alloc, hash_size); + sh->header.ref_count = 1; + add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE); + if (proto) + js_dup(JS_MKPTR(JS_TAG_OBJECT, proto)); + sh->proto = proto; + memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) * + hash_size); + sh->prop_hash_mask = hash_size - 1; + sh->prop_size = prop_size; + sh->prop_count = 0; + sh->deleted_prop_count = 0; + + /* insert in the hash table */ + sh->hash = shape_initial_hash(proto); + sh->is_hashed = true; + sh->has_small_array_index = false; + js_shape_hash_link(ctx->rt, sh); + return sh; +} + +static JSShape *js_new_shape(JSContext *ctx, JSObject *proto) +{ + return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE, + JS_PROP_INITIAL_SIZE); +} + +/* The shape is cloned. The new shape is not inserted in the shape + hash table */ +static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1) +{ + JSShape *sh; + void *sh_alloc, *sh_alloc1; + size_t size; + JSShapeProperty *pr; + uint32_t i, hash_size; + + hash_size = sh1->prop_hash_mask + 1; + size = get_shape_size(hash_size, sh1->prop_size); + sh_alloc = js_malloc(ctx, size); + if (!sh_alloc) + return NULL; + sh_alloc1 = get_alloc_from_shape(sh1); + memcpy(sh_alloc, sh_alloc1, size); + sh = get_shape_from_alloc(sh_alloc, hash_size); + sh->header.ref_count = 1; + add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE); + sh->is_hashed = false; + if (sh->proto) { + js_dup(JS_MKPTR(JS_TAG_OBJECT, sh->proto)); + } + for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { + JS_DupAtom(ctx, pr->atom); + } + return sh; +} + +static JSShape *js_dup_shape(JSShape *sh) +{ + sh->header.ref_count++; + return sh; +} + +static void js_free_shape0(JSRuntime *rt, JSShape *sh) +{ + uint32_t i; + JSShapeProperty *pr; + + assert(sh->header.ref_count == 0); + if (sh->is_hashed) + js_shape_hash_unlink(rt, sh); + if (sh->proto != NULL) { + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); + } + pr = get_shape_prop(sh); + for(i = 0; i < sh->prop_count; i++) { + JS_FreeAtomRT(rt, pr->atom); + pr++; + } + remove_gc_object(&sh->header); + js_free_rt(rt, get_alloc_from_shape(sh)); +} + +static void js_free_shape(JSRuntime *rt, JSShape *sh) +{ + if (unlikely(--sh->header.ref_count <= 0)) { + js_free_shape0(rt, sh); + } +} + +static void js_free_shape_null(JSRuntime *rt, JSShape *sh) +{ + if (sh) + js_free_shape(rt, sh); +} + +/* make space to hold at least 'count' properties */ +static no_inline int resize_properties(JSContext *ctx, JSShape **psh, + JSObject *p, uint32_t count) +{ + JSShape *sh; + uint32_t new_size, new_hash_size, new_hash_mask, i; + JSShapeProperty *pr; + void *sh_alloc; + intptr_t h; + + sh = *psh; + new_size = max_int(count, sh->prop_size * 3 / 2); + /* Reallocate prop array first to avoid crash or size inconsistency + in case of memory allocation failure */ + if (p) { + JSProperty *new_prop; + new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); + if (unlikely(!new_prop)) + return -1; + p->prop = new_prop; + } + new_hash_size = sh->prop_hash_mask + 1; + while (new_hash_size < new_size) + new_hash_size = 2 * new_hash_size; + if (new_hash_size != (sh->prop_hash_mask + 1)) { + JSShape *old_sh; + /* resize the hash table and the properties */ + old_sh = sh; + sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); + if (!sh_alloc) + return -1; + sh = get_shape_from_alloc(sh_alloc, new_hash_size); + list_del(&old_sh->header.link); + /* copy all the fields and the properties */ + memcpy(sh, old_sh, + sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count); + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); + new_hash_mask = new_hash_size - 1; + sh->prop_hash_mask = new_hash_mask; + memset(prop_hash_end(sh) - new_hash_size, 0, + sizeof(prop_hash_end(sh)[0]) * new_hash_size); + for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) { + if (pr->atom != JS_ATOM_NULL) { + h = ((uintptr_t)pr->atom & new_hash_mask); + pr->hash_next = prop_hash_end(sh)[-h - 1]; + prop_hash_end(sh)[-h - 1] = i + 1; + } + } + js_free(ctx, get_alloc_from_shape(old_sh)); + } else { + /* only resize the properties */ + list_del(&sh->header.link); + sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh), + get_shape_size(new_hash_size, new_size)); + if (unlikely(!sh_alloc)) { + /* insert again in the GC list */ + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); + return -1; + } + sh = get_shape_from_alloc(sh_alloc, new_hash_size); + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); + } + *psh = sh; + sh->prop_size = new_size; + return 0; +} + +/* remove the deleted properties. */ +static int compact_properties(JSContext *ctx, JSObject *p) +{ + JSShape *sh, *old_sh; + void *sh_alloc; + intptr_t h; + uint32_t new_hash_size, i, j, new_hash_mask, new_size; + JSShapeProperty *old_pr, *pr; + JSProperty *prop, *new_prop; + + sh = p->shape; + assert(!sh->is_hashed); + + new_size = max_int(JS_PROP_INITIAL_SIZE, + sh->prop_count - sh->deleted_prop_count); + assert(new_size <= sh->prop_size); + + new_hash_size = sh->prop_hash_mask + 1; + while ((new_hash_size / 2) >= new_size) + new_hash_size = new_hash_size / 2; + new_hash_mask = new_hash_size - 1; + + /* resize the hash table and the properties */ + old_sh = sh; + sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); + if (!sh_alloc) + return -1; + sh = get_shape_from_alloc(sh_alloc, new_hash_size); + list_del(&old_sh->header.link); + memcpy(sh, old_sh, sizeof(JSShape)); + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); + + memset(prop_hash_end(sh) - new_hash_size, 0, + sizeof(prop_hash_end(sh)[0]) * new_hash_size); + + j = 0; + old_pr = old_sh->prop; + pr = sh->prop; + prop = p->prop; + for(i = 0; i < sh->prop_count; i++) { + if (old_pr->atom != JS_ATOM_NULL) { + pr->atom = old_pr->atom; + pr->flags = old_pr->flags; + h = ((uintptr_t)old_pr->atom & new_hash_mask); + pr->hash_next = prop_hash_end(sh)[-h - 1]; + prop_hash_end(sh)[-h - 1] = j + 1; + prop[j] = prop[i]; + j++; + pr++; + } + old_pr++; + } + assert(j == (sh->prop_count - sh->deleted_prop_count)); + sh->prop_hash_mask = new_hash_mask; + sh->prop_size = new_size; + sh->deleted_prop_count = 0; + sh->prop_count = j; + + p->shape = sh; + js_free(ctx, get_alloc_from_shape(old_sh)); + + /* reduce the size of the object properties */ + new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); + if (new_prop) + p->prop = new_prop; + return 0; +} + +static int add_shape_property(JSContext *ctx, JSShape **psh, + JSObject *p, JSAtom atom, int prop_flags) +{ + JSRuntime *rt = ctx->rt; + JSShape *sh = *psh; + JSShapeProperty *pr, *prop; + uint32_t hash_mask, new_shape_hash = 0; + intptr_t h; + + /* update the shape hash */ + if (sh->is_hashed) { + js_shape_hash_unlink(rt, sh); + new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags); + } + + if (unlikely(sh->prop_count >= sh->prop_size)) { + if (resize_properties(ctx, psh, p, sh->prop_count + 1)) { + /* in case of error, reinsert in the hash table. + sh is still valid if resize_properties() failed */ + if (sh->is_hashed) + js_shape_hash_link(rt, sh); + return -1; + } + sh = *psh; + } + if (sh->is_hashed) { + sh->hash = new_shape_hash; + js_shape_hash_link(rt, sh); + } + /* Initialize the new shape property. + The object property at p->prop[sh->prop_count] is uninitialized */ + prop = get_shape_prop(sh); + pr = &prop[sh->prop_count++]; + pr->atom = JS_DupAtom(ctx, atom); + pr->flags = prop_flags; + sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom); + /* add in hash table */ + hash_mask = sh->prop_hash_mask; + h = atom & hash_mask; + pr->hash_next = prop_hash_end(sh)[-h - 1]; + prop_hash_end(sh)[-h - 1] = sh->prop_count; + return 0; +} + +/* find a hashed empty shape matching the prototype. Return NULL if + not found */ +static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto) +{ + JSShape *sh1; + uint32_t h, h1; + + h = shape_initial_hash(proto); + h1 = get_shape_hash(h, rt->shape_hash_bits); + for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) { + if (sh1->hash == h && + sh1->proto == proto && + sh1->prop_count == 0) { + return sh1; + } + } + return NULL; +} + +/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if + not found */ +static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh, + JSAtom atom, int prop_flags) +{ + JSShape *sh1; + uint32_t h, h1, i, n; + + h = sh->hash; + h = shape_hash(h, atom); + h = shape_hash(h, prop_flags); + h1 = get_shape_hash(h, rt->shape_hash_bits); + for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) { + /* we test the hash first so that the rest is done only if the + shapes really match */ + if (sh1->hash == h && + sh1->proto == sh->proto && + sh1->prop_count == ((n = sh->prop_count) + 1)) { + for(i = 0; i < n; i++) { + if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) || + unlikely(sh1->prop[i].flags != sh->prop[i].flags)) + goto next; + } + if (unlikely(sh1->prop[n].atom != atom) || + unlikely(sh1->prop[n].flags != prop_flags)) + goto next; + return sh1; + } + next: ; + } + return NULL; +} + +static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh) +{ + char atom_buf[ATOM_GET_STR_BUF_SIZE]; + int j; + + /* XXX: should output readable class prototype */ + printf("%5d %3d%c %14p %5d %5d", i, + sh->header.ref_count, " *"[sh->is_hashed], + (void *)sh->proto, sh->prop_size, sh->prop_count); + for(j = 0; j < sh->prop_count; j++) { + printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), + sh->prop[j].atom)); + } + printf("\n"); +} + +static __maybe_unused void JS_DumpShapes(JSRuntime *rt) +{ + int i; + JSShape *sh; + struct list_head *el; + JSObject *p; + JSGCObjectHeader *gp; + + printf("JSShapes: {\n"); + printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS"); + for(i = 0; i < rt->shape_hash_size; i++) { + for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) { + JS_DumpShape(rt, i, sh); + assert(sh->is_hashed); + } + } + /* dump non-hashed shapes */ + list_for_each(el, &rt->gc_obj_list) { + gp = list_entry(el, JSGCObjectHeader, link); + if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { + p = (JSObject *)gp; + if (!p->shape->is_hashed) { + JS_DumpShape(rt, -1, p->shape); + } + } + } + printf("}\n"); +} + +static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id) +{ + JSObject *p; + + js_trigger_gc(ctx->rt, sizeof(JSObject)); + p = js_malloc(ctx, sizeof(JSObject)); + if (unlikely(!p)) + goto fail; + p->class_id = class_id; + p->extensible = true; + p->free_mark = 0; + p->is_exotic = 0; + p->fast_array = 0; + p->is_constructor = 0; + p->is_uncatchable_error = 0; + p->tmp_mark = 0; + p->is_HTMLDDA = 0; + p->first_weak_ref = NULL; + p->u.opaque = NULL; + p->shape = sh; + p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size); + if (unlikely(!p->prop)) { + js_free(ctx, p); + fail: + js_free_shape(ctx->rt, sh); + return JS_EXCEPTION; + } + + switch(class_id) { + case JS_CLASS_OBJECT: + break; + case JS_CLASS_ARRAY: + { + JSProperty *pr; + p->is_exotic = 1; + p->fast_array = 1; + p->u.array.u.values = NULL; + p->u.array.count = 0; + p->u.array.u1.size = 0; + /* the length property is always the first one */ + if (likely(sh == ctx->array_shape)) { + pr = &p->prop[0]; + } else { + /* only used for the first array */ + /* cannot fail */ + pr = add_property(ctx, p, JS_ATOM_length, + JS_PROP_WRITABLE | JS_PROP_LENGTH); + } + pr->u.value = js_int32(0); + } + break; + case JS_CLASS_C_FUNCTION: + p->prop[0].u.value = JS_UNDEFINED; + break; + case JS_CLASS_ARGUMENTS: + case JS_CLASS_UINT8C_ARRAY: + case JS_CLASS_INT8_ARRAY: + case JS_CLASS_UINT8_ARRAY: + case JS_CLASS_INT16_ARRAY: + case JS_CLASS_UINT16_ARRAY: + case JS_CLASS_INT32_ARRAY: + case JS_CLASS_UINT32_ARRAY: + case JS_CLASS_BIG_INT64_ARRAY: + case JS_CLASS_BIG_UINT64_ARRAY: + case JS_CLASS_FLOAT16_ARRAY: + case JS_CLASS_FLOAT32_ARRAY: + case JS_CLASS_FLOAT64_ARRAY: + p->is_exotic = 1; + p->fast_array = 1; + p->u.array.u.ptr = NULL; + p->u.array.count = 0; + break; + case JS_CLASS_DATAVIEW: + p->u.array.u.ptr = NULL; + p->u.array.count = 0; + break; + case JS_CLASS_NUMBER: + case JS_CLASS_STRING: + case JS_CLASS_BOOLEAN: + case JS_CLASS_SYMBOL: + case JS_CLASS_DATE: + case JS_CLASS_BIG_INT: + p->u.object_data = JS_UNDEFINED; + goto set_exotic; + case JS_CLASS_REGEXP: + p->u.regexp.pattern = NULL; + p->u.regexp.bytecode = NULL; + goto set_exotic; + default: + set_exotic: + if (ctx->rt->class_array[class_id].exotic) { + p->is_exotic = 1; + } + break; + } + p->header.ref_count = 1; + add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT); + return JS_MKPTR(JS_TAG_OBJECT, p); +} + +static JSObject *get_proto_obj(JSValueConst proto_val) +{ + if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) + return NULL; + else + return JS_VALUE_GET_OBJ(proto_val); +} + +/* WARNING: proto must be an object or JS_NULL */ +JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val, + JSClassID class_id) +{ + JSShape *sh; + JSObject *proto; + + proto = get_proto_obj(proto_val); + sh = find_hashed_shape_proto(ctx->rt, proto); + if (likely(sh)) { + sh = js_dup_shape(sh); + } else { + sh = js_new_shape(ctx, proto); + if (!sh) + return JS_EXCEPTION; + } + return JS_NewObjectFromShape(ctx, sh, class_id); +} + +static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val) +{ + JSObject *p; + + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { + p = JS_VALUE_GET_OBJ(obj); + switch(p->class_id) { + case JS_CLASS_NUMBER: + case JS_CLASS_STRING: + case JS_CLASS_BOOLEAN: + case JS_CLASS_SYMBOL: + case JS_CLASS_DATE: + case JS_CLASS_BIG_INT: + JS_FreeValue(ctx, p->u.object_data); + p->u.object_data = val; + return 0; + } + } + JS_FreeValue(ctx, val); + if (!JS_IsException(obj)) + JS_ThrowTypeError(ctx, "invalid object type"); + return -1; +} + +JSValue JS_NewObjectClass(JSContext *ctx, JSClassID class_id) +{ + return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id); +} + +JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto) +{ + return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT); +} + +JSValue JS_NewObjectFrom(JSContext *ctx, int count, const JSAtom *props, + const JSValue *values) +{ + JSShapeProperty *pr; + uint32_t *hash; + JSRuntime *rt; + JSObject *p; + JSShape *sh; + JSValue obj; + JSAtom atom; + intptr_t h; + int i; + + rt = ctx->rt; + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) + return JS_EXCEPTION; + if (count > 0) { + p = JS_VALUE_GET_OBJ(obj); + sh = p->shape; + assert(sh->is_hashed); + assert(sh->header.ref_count == 1); + js_shape_hash_unlink(rt, sh); + if (resize_properties(ctx, &sh, p, count)) { + js_shape_hash_link(rt, sh); + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + p->shape = sh; + for (i = 0; i < count; i++) { + atom = props[i]; + pr = &sh->prop[i]; + sh->hash = shape_hash(shape_hash(sh->hash, atom), JS_PROP_C_W_E); + sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom); + h = atom & sh->prop_hash_mask; + hash = &prop_hash_end(sh)[-h - 1]; + pr->hash_next = *hash; + *hash = i + 1; + pr->atom = JS_DupAtom(ctx, atom); + pr->flags = JS_PROP_C_W_E; + p->prop[i].u.value = values[i]; + } + js_shape_hash_link(rt, sh); + sh->prop_count = count; + } + return obj; +} + +JSValue JS_NewObjectFromStr(JSContext *ctx, int count, const char **props, + const JSValue *values) +{ + JSAtom atoms_s[16], *atoms = atoms_s; + JSValue ret; + int i; + + i = 0; + ret = JS_EXCEPTION; + if (count < 1) + goto out; + if (count > (int)countof(atoms_s)) { + atoms = js_malloc(ctx, count * sizeof(*atoms)); + if (!atoms) + return JS_EXCEPTION; + } + for (i = 0; i < count; i++) { + atoms[i] = JS_NewAtom(ctx, props[i]); + if (atoms[i] == JS_ATOM_NULL) + goto out; + } + ret = JS_NewObjectFrom(ctx, count, atoms, values); +out: + while (i-- > 0) + JS_FreeAtom(ctx, atoms[i]); + if (atoms != atoms_s) + js_free(ctx, atoms); + return ret; +} + +JSValue JS_NewArray(JSContext *ctx) +{ + return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape), + JS_CLASS_ARRAY); +} + +// note: takes ownership of |values|, unlike js_create_array +JSValue JS_NewArrayFrom(JSContext *ctx, int count, const JSValue *values) +{ + JSObject *p; + JSValue obj; + int i; + + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) + goto exception; + if (count > 0) { + p = JS_VALUE_GET_OBJ(obj); + if (expand_fast_array(ctx, p, count)) { + JS_FreeValue(ctx, obj); + goto exception; + } + p->u.array.count = count; + p->prop[0].u.value = js_int32(count); + memcpy(p->u.array.u.values, values, count * sizeof(*values)); + } + return obj; +exception: + for (i = 0; i < count; i++) + JS_FreeValue(ctx, values[i]); + return JS_EXCEPTION; +} + +JSValue JS_NewObject(JSContext *ctx) +{ + /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */ + return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT); +} + +static void js_function_set_properties(JSContext *ctx, JSValue func_obj, + JSAtom name, int len) +{ + /* ES6 feature non compatible with ES5.1: length is configurable */ + JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, js_int32(len), + JS_PROP_CONFIGURABLE); + JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, + JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE); +} + +static bool js_class_has_bytecode(JSClassID class_id) +{ + return (class_id == JS_CLASS_BYTECODE_FUNCTION || + class_id == JS_CLASS_GENERATOR_FUNCTION || + class_id == JS_CLASS_ASYNC_FUNCTION || + class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION); +} + +/* return NULL without exception if not a function or no bytecode */ +static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return NULL; + p = JS_VALUE_GET_OBJ(val); + if (!js_class_has_bytecode(p->class_id)) + return NULL; + return p->u.func.function_bytecode; +} + +static void js_method_set_home_object(JSContext *ctx, JSValue func_obj, + JSValue home_obj) +{ + JSObject *p, *p1; + JSFunctionBytecode *b; + + if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) + return; + p = JS_VALUE_GET_OBJ(func_obj); + if (!js_class_has_bytecode(p->class_id)) + return; + b = p->u.func.function_bytecode; + if (b->need_home_object) { + p1 = p->u.func.home_object; + if (p1) { + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); + } + if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT) + p1 = JS_VALUE_GET_OBJ(js_dup(home_obj)); + else + p1 = NULL; + p->u.func.home_object = p1; + } +} + +static JSValue js_get_function_name(JSContext *ctx, JSAtom name) +{ + JSValue name_str; + + name_str = JS_AtomToString(ctx, name); + if (JS_AtomSymbolHasDescription(ctx, name)) { + name_str = JS_ConcatString3(ctx, "[", name_str, "]"); + } + return name_str; +} + +/* Modify the name of a method according to the atom and + 'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and + JS_PROP_HAS_SET. Also set the home object of the method. + Return < 0 if exception. */ +static int js_method_set_properties(JSContext *ctx, JSValue func_obj, + JSAtom name, int flags, JSValue home_obj) +{ + JSValue name_str; + + name_str = js_get_function_name(ctx, name); + if (flags & JS_PROP_HAS_GET) { + name_str = JS_ConcatString3(ctx, "get ", name_str, ""); + } else if (flags & JS_PROP_HAS_SET) { + name_str = JS_ConcatString3(ctx, "set ", name_str, ""); + } + if (JS_IsException(name_str)) + return -1; + if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str, + JS_PROP_CONFIGURABLE) < 0) + return -1; + js_method_set_home_object(ctx, func_obj, home_obj); + return 0; +} + +/* Note: at least 'length' arguments will be readable in 'argv' */ +/* `name` may be NULL, pure ASCII or UTF-8 encoded */ +JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func, + const char *name, + int length, JSCFunctionEnum cproto, int magic, + JSValueConst proto_val) +{ + JSValue func_obj; + JSObject *p; + JSAtom name_atom; + + func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION); + if (JS_IsException(func_obj)) + return func_obj; + p = JS_VALUE_GET_OBJ(func_obj); + p->u.cfunc.realm = JS_DupContext(ctx); + p->u.cfunc.c_function.generic = func; + p->u.cfunc.length = length; + p->u.cfunc.cproto = cproto; + p->u.cfunc.magic = magic; + p->is_constructor = (cproto == JS_CFUNC_constructor || + cproto == JS_CFUNC_constructor_magic || + cproto == JS_CFUNC_constructor_or_func || + cproto == JS_CFUNC_constructor_or_func_magic); + name_atom = JS_ATOM_empty_string; + if (name && *name) { + name_atom = JS_NewAtom(ctx, name); + if (name_atom == JS_ATOM_NULL) { + JS_FreeValue(ctx, func_obj); + return JS_EXCEPTION; + } + } + js_function_set_properties(ctx, func_obj, name_atom, length); + JS_FreeAtom(ctx, name_atom); + return func_obj; +} + +/* Note: at least 'length' arguments will be readable in 'argv' */ +JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, + const char *name, + int length, JSCFunctionEnum cproto, int magic) +{ + return JS_NewCFunction3(ctx, func, name, length, cproto, magic, + ctx->function_proto); +} + +typedef struct JSCFunctionDataRecord { + JSCFunctionData *func; + uint8_t length; + uint8_t data_len; + uint16_t magic; + JSValue data[]; +} JSCFunctionDataRecord; + +static void js_c_function_data_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA); + int i; + + if (s) { + for(i = 0; i < s->data_len; i++) { + JS_FreeValueRT(rt, s->data[i]); + } + js_free_rt(rt, s); + } +} + +static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA); + int i; + + if (s) { + for(i = 0; i < s->data_len; i++) { + JS_MarkValue(rt, s->data[i], mark_func); + } + } +} + +static JSValue js_call_c_function_data(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_val, + int argc, JSValueConst *argv, int flags) +{ + JSRuntime *rt = ctx->rt; + JSStackFrame sf_s, *sf = &sf_s, *prev_sf; + JSCFunctionDataRecord *s; + JSValueConst *arg_buf; + JSValue ret; + size_t stack_size; + int arg_count; + int i; + + s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA); + if (!s) + return JS_EXCEPTION; // can't really happen + arg_buf = argv; + arg_count = s->length; + if (unlikely(argc < arg_count)) { + stack_size = arg_count * sizeof(arg_buf[0]); + if (js_check_stack_overflow(rt, stack_size)) + return JS_ThrowStackOverflow(ctx); + arg_buf = alloca(stack_size); + for(i = 0; i < argc; i++) + arg_buf[i] = argv[i]; + for(i = argc; i < arg_count; i++) + arg_buf[i] = JS_UNDEFINED; + } + prev_sf = rt->current_stack_frame; + sf->prev_frame = prev_sf; + rt->current_stack_frame = sf; + // TODO(bnoordhuis) switch realms like js_call_c_function does + sf->is_strict_mode = false; + sf->cur_func = unsafe_unconst(func_obj); + sf->arg_count = argc; + ret = s->func(ctx, this_val, argc, arg_buf, s->magic, vc(s->data)); + rt->current_stack_frame = sf->prev_frame; + return ret; +} + +JSValue JS_NewCFunctionData2(JSContext *ctx, JSCFunctionData *func, + const char *name, + int length, int magic, int data_len, + JSValueConst *data) +{ + JSCFunctionDataRecord *s; + JSAtom name_atom; + JSValue func_obj; + int i; + + func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto, + JS_CLASS_C_FUNCTION_DATA); + if (JS_IsException(func_obj)) + return func_obj; + s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue)); + if (!s) { + JS_FreeValue(ctx, func_obj); + return JS_EXCEPTION; + } + s->func = func; + s->length = length; + s->data_len = data_len; + s->magic = magic; + for(i = 0; i < data_len; i++) + s->data[i] = js_dup(data[i]); + JS_SetOpaqueInternal(func_obj, s); + name_atom = JS_ATOM_empty_string; + if (name && *name) { + name_atom = JS_NewAtom(ctx, name); + if (name_atom == JS_ATOM_NULL) { + JS_FreeValue(ctx, func_obj); + return JS_EXCEPTION; + } + } + js_function_set_properties(ctx, func_obj, name_atom, length); + JS_FreeAtom(ctx, name_atom); + return func_obj; +} + +JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, + int length, int magic, int data_len, + JSValueConst *data) +{ + return JS_NewCFunctionData2(ctx, func, NULL, length, magic, data_len, data); +} + +static JSContext *js_autoinit_get_realm(JSProperty *pr) +{ + return (JSContext *)(pr->u.init.realm_and_id & ~3); +} + +static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr) +{ + return pr->u.init.realm_and_id & 3; +} + +static void js_autoinit_free(JSRuntime *rt, JSProperty *pr) +{ + JS_FreeContext(js_autoinit_get_realm(pr)); +} + +static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr, + JS_MarkFunc *mark_func) +{ + mark_func(rt, &js_autoinit_get_realm(pr)->header); +} + +typedef struct JSCClosureRecord { + JSCClosure *func; + uint16_t length; + uint16_t magic; + void *opaque; + void (*opaque_finalize)(void *opaque); +} JSCClosureRecord; + +static void js_c_closure_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSCClosureRecord *s = JS_GetOpaque(val, JS_CLASS_C_CLOSURE); + + if (s) { + if (s->opaque_finalize) + s->opaque_finalize(s->opaque); + + js_free_rt(rt, s); + } +} + +static JSValue js_call_c_closure(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_val, + int argc, JSValueConst *argv, int flags) +{ + JSRuntime *rt = ctx->rt; + JSStackFrame sf_s, *sf = &sf_s, *prev_sf; + JSCClosureRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_CLOSURE); + JSValueConst *arg_buf; + JSValue ret; + int arg_count; + int i; + size_t stack_size; + + arg_buf = argv; + arg_count = s->length; + if (unlikely(argc < arg_count)) { + stack_size = arg_count * sizeof(arg_buf[0]); + if (js_check_stack_overflow(rt, stack_size)) + return JS_ThrowStackOverflow(ctx); + arg_buf = alloca(stack_size); + for (i = 0; i < argc; i++) + arg_buf[i] = argv[i]; + for (i = argc; i < arg_count; i++) + arg_buf[i] = JS_UNDEFINED; + } + + prev_sf = rt->current_stack_frame; + sf->prev_frame = prev_sf; + rt->current_stack_frame = sf; + // TODO(bnoordhuis) switch realms like js_call_c_function does + sf->is_strict_mode = false; + sf->cur_func = unsafe_unconst(func_obj); + sf->arg_count = argc; + ret = s->func(ctx, this_val, argc, arg_buf, s->magic, s->opaque); + rt->current_stack_frame = sf->prev_frame; + + return ret; +} + +JSValue JS_NewCClosure(JSContext *ctx, JSCClosure *func, const char *name, + JSCClosureFinalizerFunc *opaque_finalize, + int length, int magic, void *opaque) +{ + JSCClosureRecord *s; + JSAtom name_atom; + JSValue func_obj; + + func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto, + JS_CLASS_C_CLOSURE); + if (JS_IsException(func_obj)) + return func_obj; + s = js_malloc(ctx, sizeof(*s)); + if (!s) { + JS_FreeValue(ctx, func_obj); + return JS_EXCEPTION; + } + s->func = func; + s->length = length; + s->magic = magic; + s->opaque = opaque; + s->opaque_finalize = opaque_finalize; + JS_SetOpaqueInternal(func_obj, s); + name_atom = JS_ATOM_empty_string; + if (name && *name) { + name_atom = JS_NewAtom(ctx, name); + if (name_atom == JS_ATOM_NULL) { + JS_FreeValue(ctx, func_obj); + return JS_EXCEPTION; + } + } + js_function_set_properties(ctx, func_obj, name_atom, length); + JS_FreeAtom(ctx, name_atom); + return func_obj; +} + +static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags) +{ + if (unlikely(prop_flags & JS_PROP_TMASK)) { + if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) { + if (pr->u.getset.getter) + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); + if (pr->u.getset.setter) + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); + } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + free_var_ref(rt, pr->u.var_ref); + } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + js_autoinit_free(rt, pr); + } + } else { + JS_FreeValueRT(rt, pr->u.value); + } +} + +static force_inline JSShapeProperty *find_own_property1(JSObject *p, + JSAtom atom) +{ + JSShape *sh; + JSShapeProperty *pr, *prop; + intptr_t h; + sh = p->shape; + h = (uintptr_t)atom & sh->prop_hash_mask; + h = prop_hash_end(sh)[-h - 1]; + prop = get_shape_prop(sh); + while (h) { + pr = &prop[h - 1]; + if (likely(pr->atom == atom)) { + return pr; + } + h = pr->hash_next; + } + return NULL; +} + +static force_inline JSShapeProperty *find_own_property(JSProperty **ppr, + JSObject *p, + JSAtom atom) +{ + JSShape *sh; + JSShapeProperty *pr, *prop; + intptr_t h; + sh = p->shape; + h = (uintptr_t)atom & sh->prop_hash_mask; + h = prop_hash_end(sh)[-h - 1]; + prop = get_shape_prop(sh); + while (h) { + pr = &prop[h - 1]; + if (likely(pr->atom == atom)) { + *ppr = &p->prop[h - 1]; + /* the compiler should be able to assume that pr != NULL here */ + return pr; + } + h = pr->hash_next; + } + *ppr = NULL; + return NULL; +} + +static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref) +{ + if (var_ref) { + assert(var_ref->header.ref_count > 0); + if (--var_ref->header.ref_count == 0) { + if (var_ref->is_detached) { + JS_FreeValueRT(rt, var_ref->value); + remove_gc_object(&var_ref->header); + } else { + list_del(&var_ref->header.link); /* still on the stack */ + } + js_free_rt(rt, var_ref); + } + } +} + +static void js_array_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + int i; + + for(i = 0; i < p->u.array.count; i++) { + JS_FreeValueRT(rt, p->u.array.u.values[i]); + } + js_free_rt(rt, p->u.array.u.values); +} + +static void js_array_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + int i; + + for(i = 0; i < p->u.array.count; i++) { + JS_MarkValue(rt, p->u.array.u.values[i], mark_func); + } +} + +static void js_object_data_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JS_FreeValueRT(rt, p->u.object_data); + p->u.object_data = JS_UNDEFINED; +} + +static void js_object_data_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JS_MarkValue(rt, p->u.object_data, mark_func); +} + +static void js_c_function_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + + if (p->u.cfunc.realm) + JS_FreeContext(p->u.cfunc.realm); +} + +static void js_c_function_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + + if (p->u.cfunc.realm) + mark_func(rt, &p->u.cfunc.realm->header); +} + +static void js_bytecode_function_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSObject *p1, *p = JS_VALUE_GET_OBJ(val); + JSFunctionBytecode *b; + JSVarRef **var_refs; + int i; + + p1 = p->u.func.home_object; + if (p1) { + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1)); + } + b = p->u.func.function_bytecode; + if (b) { + var_refs = p->u.func.var_refs; + if (var_refs) { + for(i = 0; i < b->closure_var_count; i++) + free_var_ref(rt, var_refs[i]); + js_free_rt(rt, var_refs); + } + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b)); + } +} + +static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSVarRef **var_refs = p->u.func.var_refs; + JSFunctionBytecode *b = p->u.func.function_bytecode; + int i; + + if (p->u.func.home_object) { + JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object), + mark_func); + } + if (b) { + if (var_refs) { + for(i = 0; i < b->closure_var_count; i++) { + JSVarRef *var_ref = var_refs[i]; + if (var_ref && var_ref->is_detached) { + mark_func(rt, &var_ref->header); + } + } + } + /* must mark the function bytecode because template objects may be + part of a cycle */ + JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func); + } +} + +static void js_bound_function_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSBoundFunction *bf = p->u.bound_function; + int i; + + JS_FreeValueRT(rt, bf->func_obj); + JS_FreeValueRT(rt, bf->this_val); + for(i = 0; i < bf->argc; i++) { + JS_FreeValueRT(rt, bf->argv[i]); + } + js_free_rt(rt, bf); +} + +static void js_bound_function_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSBoundFunction *bf = p->u.bound_function; + int i; + + JS_MarkValue(rt, bf->func_obj, mark_func); + JS_MarkValue(rt, bf->this_val, mark_func); + for(i = 0; i < bf->argc; i++) + JS_MarkValue(rt, bf->argv[i], mark_func); +} + +static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValueConst val) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSForInIterator *it = p->u.for_in_iterator; + JS_FreeValueRT(rt, it->obj); + js_free_rt(rt, it); +} + +static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSForInIterator *it = p->u.for_in_iterator; + JS_MarkValue(rt, it->obj, mark_func); +} + +static void free_object(JSRuntime *rt, JSObject *p) +{ + int i; + JSClassFinalizer *finalizer; + JSShape *sh; + JSShapeProperty *pr; + + p->free_mark = 1; /* used to tell the object is invalid when + freeing cycles */ + /* free all the fields */ + sh = p->shape; + pr = get_shape_prop(sh); + for(i = 0; i < sh->prop_count; i++) { + free_property(rt, &p->prop[i], pr->flags); + pr++; + } + js_free_rt(rt, p->prop); + /* as an optimization we destroy the shape immediately without + putting it in gc_zero_ref_count_list */ + js_free_shape(rt, sh); + + /* fail safe */ + p->shape = NULL; + p->prop = NULL; + + if (unlikely(p->first_weak_ref)) { + reset_weak_ref(rt, &p->first_weak_ref); + } + + finalizer = rt->class_array[p->class_id].finalizer; + if (finalizer) + (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p)); + + /* fail safe */ + p->class_id = 0; + p->u.opaque = NULL; + p->u.func.var_refs = NULL; + p->u.func.home_object = NULL; + + remove_gc_object(&p->header); + if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && p->header.ref_count != 0) { + list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list); + } else { + js_free_rt(rt, p); + } +} + +static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp) +{ + switch(gp->gc_obj_type) { + case JS_GC_OBJ_TYPE_JS_OBJECT: + free_object(rt, (JSObject *)gp); + break; + case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: + free_function_bytecode(rt, (JSFunctionBytecode *)gp); + break; + default: + abort(); + } +} + +static void free_zero_refcount(JSRuntime *rt) +{ + struct list_head *el; + JSGCObjectHeader *p; + + rt->gc_phase = JS_GC_PHASE_DECREF; + for(;;) { + el = rt->gc_zero_ref_count_list.next; + if (el == &rt->gc_zero_ref_count_list) + break; + p = list_entry(el, JSGCObjectHeader, link); + assert(p->ref_count == 0); + free_gc_object(rt, p); + } + rt->gc_phase = JS_GC_PHASE_NONE; +} + +/* called with the ref_count of 'v' reaches zero. */ +static void js_free_value_rt(JSRuntime *rt, JSValue v) +{ + uint32_t tag = JS_VALUE_GET_TAG(v); + +#ifdef ENABLE_DUMPS // JS_DUMP_FREE + if (check_dump_flag(rt, JS_DUMP_FREE)) { + /* Prevent invalid object access during GC */ + if ((rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) + || (tag != JS_TAG_OBJECT && tag != JS_TAG_FUNCTION_BYTECODE)) { + printf("Freeing "); + if (tag == JS_TAG_OBJECT) { + JS_DumpObject(rt, JS_VALUE_GET_OBJ(v)); + } else { + JS_DumpValue(rt, v); + printf("\n"); + } + } + } +#endif + + switch(tag) { + case JS_TAG_STRING: + js_free_string0(rt, JS_VALUE_GET_STRING(v)); + break; + case JS_TAG_OBJECT: + case JS_TAG_FUNCTION_BYTECODE: + { + JSGCObjectHeader *p = JS_VALUE_GET_PTR(v); + if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) { + list_del(&p->link); + list_add(&p->link, &rt->gc_zero_ref_count_list); + if (rt->gc_phase == JS_GC_PHASE_NONE) { + free_zero_refcount(rt); + } + } + } + break; + case JS_TAG_MODULE: + abort(); /* never freed here */ + break; + case JS_TAG_BIG_INT: + { + JSBigInt *p = JS_VALUE_GET_PTR(v); + js_free_rt(rt, p); + } + break; + case JS_TAG_SYMBOL: + { + JSAtomStruct *p = JS_VALUE_GET_PTR(v); + JS_FreeAtomStruct(rt, p); + } + break; + default: + printf("js_free_value_rt: unknown tag=%d\n", tag); + abort(); + } +} + +void JS_FreeValueRT(JSRuntime *rt, JSValue v) +{ + if (JS_VALUE_HAS_REF_COUNT(v)) { + JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); + if (--p->ref_count <= 0) { + js_free_value_rt(rt, v); + } + } +} + +void JS_FreeValue(JSContext *ctx, JSValue v) +{ + JS_FreeValueRT(ctx->rt, v); +} + +/* garbage collection */ + +static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, + JSGCObjectTypeEnum type) +{ + h->mark = 0; + h->gc_obj_type = type; + list_add_tail(&h->link, &rt->gc_obj_list); +} + +static void remove_gc_object(JSGCObjectHeader *h) +{ + list_del(&h->link); +} + +void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) +{ + if (JS_VALUE_HAS_REF_COUNT(val)) { + switch(JS_VALUE_GET_TAG(val)) { + case JS_TAG_OBJECT: + case JS_TAG_FUNCTION_BYTECODE: + mark_func(rt, JS_VALUE_GET_PTR(val)); + break; + default: + break; + } + } +} + +static void mark_weak_map_value(JSRuntime *rt, JSWeakRefRecord *first_weak_ref, JS_MarkFunc *mark_func) { + JSWeakRefRecord *wr; + JSMapRecord *mr; + JSMapState *s; + + for (wr = first_weak_ref; wr != NULL; wr = wr->next_weak_ref) { + if (wr->kind == JS_WEAK_REF_KIND_MAP) { + mr = wr->u.map_record; + s = mr->map; + assert(s->is_weak); + assert(!mr->empty); /* no iterator on WeakMap/WeakSet */ + JS_MarkValue(rt, mr->value, mark_func); + } + } +} + +static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, + JS_MarkFunc *mark_func) +{ + switch(gp->gc_obj_type) { + case JS_GC_OBJ_TYPE_JS_OBJECT: + { + JSObject *p = (JSObject *)gp; + JSShapeProperty *prs; + JSShape *sh; + int i; + sh = p->shape; + mark_func(rt, &sh->header); + /* mark all the fields */ + prs = get_shape_prop(sh); + for(i = 0; i < sh->prop_count; i++) { + JSProperty *pr = &p->prop[i]; + if (prs->atom != JS_ATOM_NULL) { + if (prs->flags & JS_PROP_TMASK) { + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { + if (pr->u.getset.getter) + mark_func(rt, &pr->u.getset.getter->header); + if (pr->u.getset.setter) + mark_func(rt, &pr->u.getset.setter->header); + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + if (pr->u.var_ref->is_detached) { + /* Note: the tag does not matter + provided it is a GC object */ + mark_func(rt, &pr->u.var_ref->header); + } + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + js_autoinit_mark(rt, pr, mark_func); + } + } else { + JS_MarkValue(rt, pr->u.value, mark_func); + } + } + prs++; + } + + if (unlikely(p->first_weak_ref)) { + mark_weak_map_value(rt, p->first_weak_ref, mark_func); + } + + if (p->class_id != JS_CLASS_OBJECT) { + JSClassGCMark *gc_mark; + gc_mark = rt->class_array[p->class_id].gc_mark; + if (gc_mark) + gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func); + } + } + break; + case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: + /* the template objects can be part of a cycle */ + { + JSFunctionBytecode *b = (JSFunctionBytecode *)gp; + int i; + for(i = 0; i < b->cpool_count; i++) { + JS_MarkValue(rt, b->cpool[i], mark_func); + } + if (b->realm) + mark_func(rt, &b->realm->header); + } + break; + case JS_GC_OBJ_TYPE_VAR_REF: + { + JSVarRef *var_ref = (JSVarRef *)gp; + /* only detached variable referenced are taken into account */ + assert(var_ref->is_detached); + JS_MarkValue(rt, *var_ref->pvalue, mark_func); + } + break; + case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: + { + JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp; + if (s->is_active) + async_func_mark(rt, &s->func_state, mark_func); + JS_MarkValue(rt, s->resolving_funcs[0], mark_func); + JS_MarkValue(rt, s->resolving_funcs[1], mark_func); + } + break; + case JS_GC_OBJ_TYPE_SHAPE: + { + JSShape *sh = (JSShape *)gp; + if (sh->proto != NULL) { + mark_func(rt, &sh->proto->header); + } + } + break; + case JS_GC_OBJ_TYPE_JS_CONTEXT: + { + JSContext *ctx = (JSContext *)gp; + JS_MarkContext(rt, ctx, mark_func); + } + break; + default: + abort(); + } +} + +static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p) +{ + assert(p->ref_count > 0); + p->ref_count--; + if (p->ref_count == 0 && p->mark == 1) { + list_del(&p->link); + list_add_tail(&p->link, &rt->tmp_obj_list); + } +} + +static void gc_decref(JSRuntime *rt) +{ + struct list_head *el, *el1; + JSGCObjectHeader *p; + + init_list_head(&rt->tmp_obj_list); + + /* decrement the refcount of all the children of all the GC + objects and move the GC objects with zero refcount to + tmp_obj_list */ + list_for_each_safe(el, el1, &rt->gc_obj_list) { + p = list_entry(el, JSGCObjectHeader, link); + assert(p->mark == 0); + mark_children(rt, p, gc_decref_child); + p->mark = 1; + if (p->ref_count == 0) { + list_del(&p->link); + list_add_tail(&p->link, &rt->tmp_obj_list); + } + } +} + +static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p) +{ + p->ref_count++; + if (p->ref_count == 1) { + /* ref_count was 0: remove from tmp_obj_list and add at the + end of gc_obj_list */ + list_del(&p->link); + list_add_tail(&p->link, &rt->gc_obj_list); + p->mark = 0; /* reset the mark for the next GC call */ + } +} + +static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p) +{ + p->ref_count++; +} + +static void gc_scan(JSRuntime *rt) +{ + struct list_head *el; + JSGCObjectHeader *p; + + /* keep the objects with a refcount > 0 and their children. */ + list_for_each(el, &rt->gc_obj_list) { + p = list_entry(el, JSGCObjectHeader, link); + assert(p->ref_count > 0); + p->mark = 0; /* reset the mark for the next GC call */ + mark_children(rt, p, gc_scan_incref_child); + } + + /* restore the refcount of the objects to be deleted. */ + list_for_each(el, &rt->tmp_obj_list) { + p = list_entry(el, JSGCObjectHeader, link); + mark_children(rt, p, gc_scan_incref_child2); + } +} + +static void gc_free_cycles(JSRuntime *rt) +{ + struct list_head *el, *el1; + JSGCObjectHeader *p; +#ifdef ENABLE_DUMPS // JS_DUMP_GC_FREE + bool header_done = false; +#endif + + rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES; + + for(;;) { + el = rt->tmp_obj_list.next; + if (el == &rt->tmp_obj_list) + break; + p = list_entry(el, JSGCObjectHeader, link); + /* Only need to free the GC object associated with JS + values. The rest will be automatically removed because they + must be referenced by them. */ + switch(p->gc_obj_type) { + case JS_GC_OBJ_TYPE_JS_OBJECT: + case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: +#ifdef ENABLE_DUMPS // JS_DUMP_GC_FREE + if (check_dump_flag(rt, JS_DUMP_GC_FREE)) { + if (!header_done) { + printf("Freeing cycles:\n"); + JS_DumpObjectHeader(rt); + header_done = true; + } + JS_DumpGCObject(rt, p); + } +#endif + free_gc_object(rt, p); + break; + default: + list_del(&p->link); + list_add_tail(&p->link, &rt->gc_zero_ref_count_list); + break; + } + } + rt->gc_phase = JS_GC_PHASE_NONE; + + list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) { + p = list_entry(el, JSGCObjectHeader, link); + assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || + p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); + js_free_rt(rt, p); + } + + init_list_head(&rt->gc_zero_ref_count_list); +} + +void JS_RunGC(JSRuntime *rt) +{ + /* decrement the reference of the children of each object. mark = + 1 after this pass. */ + gc_decref(rt); + + /* keep the GC objects with a non zero refcount and their childs */ + gc_scan(rt); + + /* free the GC objects in a cycle */ + gc_free_cycles(rt); +} + +/* Return false if not an object or if the object has already been + freed (zombie objects are visible in finalizers when freeing + cycles). */ +bool JS_IsLiveObject(JSRuntime *rt, JSValueConst obj) +{ + JSObject *p; + if (!JS_IsObject(obj)) + return false; + p = JS_VALUE_GET_OBJ(obj); + return !p->free_mark; +} + +/* Compute memory used by various object types */ +/* XXX: poor man's approach to handling multiply referenced objects */ +typedef struct JSMemoryUsage_helper { + double memory_used_count; + double str_count; + double str_size; + int64_t js_func_count; + double js_func_size; + int64_t js_func_code_size; + int64_t js_func_pc2line_count; + int64_t js_func_pc2line_size; +} JSMemoryUsage_helper; + +static void compute_value_size(JSValue val, JSMemoryUsage_helper *hp); + +static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp) +{ + if (!str->atom_type) { /* atoms are handled separately */ + double s_ref_count = str->header.ref_count; + hp->str_count += 1 / s_ref_count; + hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) + + 1 - str->is_wide_char) / s_ref_count); + } +} + +static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp) +{ + int memory_used_count, js_func_size, i; + + memory_used_count = 0; + js_func_size = sizeof(*b); + if (b->vardefs) { + js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs); + } + if (b->cpool) { + js_func_size += b->cpool_count * sizeof(*b->cpool); + for (i = 0; i < b->cpool_count; i++) { + JSValue val = b->cpool[i]; + compute_value_size(val, hp); + } + } + if (b->closure_var) { + js_func_size += b->closure_var_count * sizeof(*b->closure_var); + } + if (b->byte_code_buf) { + hp->js_func_code_size += b->byte_code_len; + } + memory_used_count++; + js_func_size += b->source_len + 1; + if (b->pc2line_len) { + memory_used_count++; + hp->js_func_pc2line_count += 1; + hp->js_func_pc2line_size += b->pc2line_len; + } + hp->js_func_size += js_func_size; + hp->js_func_count += 1; + hp->memory_used_count += memory_used_count; +} + +static void compute_value_size(JSValue val, JSMemoryUsage_helper *hp) +{ + switch(JS_VALUE_GET_TAG(val)) { + case JS_TAG_STRING: + compute_jsstring_size(JS_VALUE_GET_STRING(val), hp); + break; + case JS_TAG_BIG_INT: + /* should track JSBigInt usage */ + break; + } +} + +void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) +{ + struct list_head *el, *el1; + int i; + JSMemoryUsage_helper mem = { 0 }, *hp = &mem; + + memset(s, 0, sizeof(*s)); + s->malloc_count = rt->malloc_state.malloc_count; + s->malloc_size = rt->malloc_state.malloc_size; + s->malloc_limit = rt->malloc_state.malloc_limit; + + s->memory_used_count = 2; /* rt + rt->class_array */ + s->memory_used_size = sizeof(JSRuntime) + sizeof(JSClass) * rt->class_count; + + list_for_each(el, &rt->context_list) { + JSContext *ctx = list_entry(el, JSContext, link); + JSShape *sh = ctx->array_shape; + s->memory_used_count += 2; /* ctx + ctx->class_proto */ + s->memory_used_size += sizeof(JSContext) + + sizeof(JSValue) * rt->class_count; + s->binary_object_count += ctx->binary_object_count; + s->binary_object_size += ctx->binary_object_size; + + /* the hashed shapes are counted separately */ + if (sh && !sh->is_hashed) { + int hash_size = sh->prop_hash_mask + 1; + s->shape_count++; + s->shape_size += get_shape_size(hash_size, sh->prop_size); + } + list_for_each(el1, &ctx->loaded_modules) { + JSModuleDef *m = list_entry(el1, JSModuleDef, link); + s->memory_used_count += 1; + s->memory_used_size += sizeof(*m); + if (m->req_module_entries) { + s->memory_used_count += 1; + s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries); + } + if (m->export_entries) { + s->memory_used_count += 1; + s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries); + for (i = 0; i < m->export_entries_count; i++) { + JSExportEntry *me = &m->export_entries[i]; + if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) { + /* potential multiple count */ + s->memory_used_count += 1; + compute_value_size(me->u.local.var_ref->value, hp); + } + } + } + if (m->star_export_entries) { + s->memory_used_count += 1; + s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries); + } + if (m->import_entries) { + s->memory_used_count += 1; + s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries); + } + compute_value_size(m->module_ns, hp); + compute_value_size(m->func_obj, hp); + } + } + + list_for_each(el, &rt->gc_obj_list) { + JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link); + JSObject *p; + JSShape *sh; + JSShapeProperty *prs; + + /* XXX: could count the other GC object types too */ + if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) { + compute_bytecode_size((JSFunctionBytecode *)gp, hp); + continue; + } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) { + continue; + } + p = (JSObject *)gp; + sh = p->shape; + s->obj_count++; + if (p->prop) { + s->memory_used_count++; + s->prop_size += sh->prop_size * sizeof(*p->prop); + s->prop_count += sh->prop_count; + prs = get_shape_prop(sh); + for(i = 0; i < sh->prop_count; i++) { + JSProperty *pr = &p->prop[i]; + if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) { + compute_value_size(pr->u.value, hp); + } + prs++; + } + } + /* the hashed shapes are counted separately */ + if (!sh->is_hashed) { + int hash_size = sh->prop_hash_mask + 1; + s->shape_count++; + s->shape_size += get_shape_size(hash_size, sh->prop_size); + } + + switch(p->class_id) { + case JS_CLASS_ARRAY: /* u.array | length */ + case JS_CLASS_ARGUMENTS: /* u.array | length */ + s->array_count++; + if (p->fast_array) { + s->fast_array_count++; + if (p->u.array.u.values) { + s->memory_used_count++; + s->memory_used_size += p->u.array.count * + sizeof(*p->u.array.u.values); + s->fast_array_elements += p->u.array.count; + for (i = 0; i < p->u.array.count; i++) { + compute_value_size(p->u.array.u.values[i], hp); + } + } + } + break; + case JS_CLASS_NUMBER: /* u.object_data */ + case JS_CLASS_STRING: /* u.object_data */ + case JS_CLASS_BOOLEAN: /* u.object_data */ + case JS_CLASS_SYMBOL: /* u.object_data */ + case JS_CLASS_DATE: /* u.object_data */ + case JS_CLASS_BIG_INT: /* u.object_data */ + compute_value_size(p->u.object_data, hp); + break; + case JS_CLASS_C_FUNCTION: /* u.cfunc */ + s->c_func_count++; + break; + case JS_CLASS_BYTECODE_FUNCTION: /* u.func */ + { + JSFunctionBytecode *b = p->u.func.function_bytecode; + JSVarRef **var_refs = p->u.func.var_refs; + /* home_object: object will be accounted for in list scan */ + if (var_refs) { + s->memory_used_count++; + s->js_func_size += b->closure_var_count * sizeof(*var_refs); + for (i = 0; i < b->closure_var_count; i++) { + if (var_refs[i]) { + double ref_count = var_refs[i]->header.ref_count; + s->memory_used_count += 1 / ref_count; + s->js_func_size += sizeof(*var_refs[i]) / ref_count; + /* handle non object closed values */ + if (var_refs[i]->pvalue == &var_refs[i]->value) { + /* potential multiple count */ + compute_value_size(var_refs[i]->value, hp); + } + } + } + } + } + break; + case JS_CLASS_BOUND_FUNCTION: /* u.bound_function */ + { + JSBoundFunction *bf = p->u.bound_function; + /* func_obj and this_val are objects */ + for (i = 0; i < bf->argc; i++) { + compute_value_size(bf->argv[i], hp); + } + s->memory_used_count += 1; + s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv); + } + break; + case JS_CLASS_C_FUNCTION_DATA: /* u.c_function_data_record */ + { + JSCFunctionDataRecord *fd = p->u.c_function_data_record; + if (fd) { + for (i = 0; i < fd->data_len; i++) { + compute_value_size(fd->data[i], hp); + } + s->memory_used_count += 1; + s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data); + } + } + break; + case JS_CLASS_C_CLOSURE: /* u.c_closure_record */ + { + JSCClosureRecord *c = p->u.c_closure_record; + if (c) { + s->memory_used_count += 1; + s->memory_used_size += sizeof(*c); + } + } + break; + case JS_CLASS_REGEXP: /* u.regexp */ + compute_jsstring_size(p->u.regexp.pattern, hp); + compute_jsstring_size(p->u.regexp.bytecode, hp); + break; + + case JS_CLASS_FOR_IN_ITERATOR: /* u.for_in_iterator */ + { + JSForInIterator *it = p->u.for_in_iterator; + if (it) { + compute_value_size(it->obj, hp); + s->memory_used_count += 1; + s->memory_used_size += sizeof(*it); + } + } + break; + case JS_CLASS_ARRAY_BUFFER: /* u.array_buffer */ + case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */ + { + JSArrayBuffer *abuf = p->u.array_buffer; + if (abuf) { + s->memory_used_count += 1; + s->memory_used_size += sizeof(*abuf); + if (abuf->data) { + s->memory_used_count += 1; + s->memory_used_size += abuf->byte_length; + } + } + } + break; + case JS_CLASS_GENERATOR: /* u.generator_data */ + case JS_CLASS_UINT8C_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_INT8_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_UINT8_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_INT16_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_UINT16_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_INT32_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_UINT32_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_FLOAT16_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_FLOAT32_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_FLOAT64_ARRAY: /* u.typed_array / u.array */ + case JS_CLASS_DATAVIEW: /* u.typed_array */ + case JS_CLASS_MAP: /* u.map_state */ + case JS_CLASS_SET: /* u.map_state */ + case JS_CLASS_WEAKMAP: /* u.map_state */ + case JS_CLASS_WEAKSET: /* u.map_state */ + case JS_CLASS_MAP_ITERATOR: /* u.map_iterator_data */ + case JS_CLASS_SET_ITERATOR: /* u.map_iterator_data */ + case JS_CLASS_ARRAY_ITERATOR: /* u.array_iterator_data */ + case JS_CLASS_STRING_ITERATOR: /* u.array_iterator_data */ + case JS_CLASS_PROXY: /* u.proxy_data */ + case JS_CLASS_PROMISE: /* u.promise_data */ + case JS_CLASS_PROMISE_RESOLVE_FUNCTION: /* u.promise_function_data */ + case JS_CLASS_PROMISE_REJECT_FUNCTION: /* u.promise_function_data */ + case JS_CLASS_ASYNC_FUNCTION_RESOLVE: /* u.async_function_data */ + case JS_CLASS_ASYNC_FUNCTION_REJECT: /* u.async_function_data */ + case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR: /* u.async_from_sync_iterator_data */ + case JS_CLASS_ASYNC_GENERATOR: /* u.async_generator_data */ + /* TODO */ + default: + /* XXX: class definition should have an opaque block size */ + if (p->u.opaque) { + s->memory_used_count += 1; + } + break; + } + } + s->obj_size += s->obj_count * sizeof(JSObject); + + /* hashed shapes */ + s->memory_used_count++; /* rt->shape_hash */ + s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size; + for(i = 0; i < rt->shape_hash_size; i++) { + JSShape *sh; + for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) { + int hash_size = sh->prop_hash_mask + 1; + s->shape_count++; + s->shape_size += get_shape_size(hash_size, sh->prop_size); + } + } + + /* atoms */ + s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */ + s->atom_count = rt->atom_count; + s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size + + sizeof(rt->atom_hash[0]) * rt->atom_hash_size; + for(i = 0; i < rt->atom_size; i++) { + JSAtomStruct *p = rt->atom_array[i]; + if (!atom_is_free(p)) { + s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) + + 1 - p->is_wide_char); + } + } + s->str_count = round(mem.str_count); + s->str_size = round(mem.str_size); + s->js_func_count = mem.js_func_count; + s->js_func_size = round(mem.js_func_size); + s->js_func_code_size = mem.js_func_code_size; + s->js_func_pc2line_count = mem.js_func_pc2line_count; + s->js_func_pc2line_size = mem.js_func_pc2line_size; + s->memory_used_count += round(mem.memory_used_count) + + s->atom_count + s->str_count + + s->obj_count + s->shape_count + + s->js_func_count + s->js_func_pc2line_count; + s->memory_used_size += s->atom_size + s->str_size + + s->obj_size + s->prop_size + s->shape_size + + s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size; +} + +void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) +{ + fprintf(fp, "QuickJS-ng memory usage -- %s version, %d-bit, %s Endian, malloc limit: %"PRId64"\n\n", + JS_GetVersion(), (int)sizeof(void *) * 8, is_be() ? "Big" : "Little", s->malloc_limit); + if (rt) { + static const struct { + const char *name; + size_t size; + } object_types[] = { + { "JSRuntime", sizeof(JSRuntime) }, + { "JSContext", sizeof(JSContext) }, + { "JSObject", sizeof(JSObject) }, + { "JSString", sizeof(JSString) }, + { "JSFunctionBytecode", sizeof(JSFunctionBytecode) }, + }; + int i, usage_size_ok = 0; + for(i = 0; i < countof(object_types); i++) { + unsigned int size = object_types[i].size; + void *p = js_malloc_rt(rt, size); + if (p) { + unsigned int size1 = js_malloc_usable_size_rt(rt, p); + if (size1 >= size) { + usage_size_ok = 1; + fprintf(fp, " %3u + %-2u %s\n", + size, size1 - size, object_types[i].name); + } + js_free_rt(rt, p); + } + } + if (!usage_size_ok) { + fprintf(fp, " malloc_usable_size unavailable\n"); + } + { + int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 }; + int class_id; + struct list_head *el; + list_for_each(el, &rt->gc_obj_list) { + JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link); + JSObject *p; + if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { + p = (JSObject *)gp; + obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++; + } + } + fprintf(fp, "\n" "JSObject classes\n"); + if (obj_classes[0]) + fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none"); + for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) { + if (obj_classes[class_id] && class_id < rt->class_count) { + char buf[ATOM_GET_STR_BUF_SIZE]; + fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id, + JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name)); + } + } + if (obj_classes[JS_CLASS_INIT_COUNT]) + fprintf(fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other"); + } + fprintf(fp, "\n"); + } + fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE"); + + if (s->malloc_count) { + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n", + "memory allocated", s->malloc_count, s->malloc_size, + (double)s->malloc_size / s->malloc_count); + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n", + "memory used", s->memory_used_count, s->memory_used_size, + MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) / + s->memory_used_count)); + } + if (s->atom_count) { + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n", + "atoms", s->atom_count, s->atom_size, + (double)s->atom_size / s->atom_count); + } + if (s->str_count) { + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n", + "strings", s->str_count, s->str_size, + (double)s->str_size / s->str_count); + } + if (s->obj_count) { + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", + "objects", s->obj_count, s->obj_size, + (double)s->obj_size / s->obj_count); + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", + " properties", s->prop_count, s->prop_size, + (double)s->prop_count / s->obj_count); + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n", + " shapes", s->shape_count, s->shape_size, + (double)s->shape_size / s->shape_count); + } + if (s->js_func_count) { + fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n", + "bytecode functions", s->js_func_count, s->js_func_size); + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", + " bytecode", s->js_func_count, s->js_func_code_size, + (double)s->js_func_code_size / s->js_func_count); + if (s->js_func_pc2line_count) { + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", + " pc2line", s->js_func_pc2line_count, + s->js_func_pc2line_size, + (double)s->js_func_pc2line_size / s->js_func_pc2line_count); + } + } + if (s->c_func_count) { + fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count); + } + if (s->array_count) { + fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count); + if (s->fast_array_count) { + fprintf(fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count); + fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n", + " elements", s->fast_array_elements, + s->fast_array_elements * (int)sizeof(JSValue), + (double)s->fast_array_elements / s->fast_array_count); + } + } + if (s->binary_object_count) { + fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n", + "binary objects", s->binary_object_count, s->binary_object_size); + } +} + +JSValue JS_GetGlobalObject(JSContext *ctx) +{ + return js_dup(ctx->global_obj); +} + +/* WARNING: obj is freed */ +JSValue JS_Throw(JSContext *ctx, JSValue obj) +{ + JSRuntime *rt = ctx->rt; + JS_FreeValue(ctx, rt->current_exception); + rt->current_exception = obj; + return JS_EXCEPTION; +} + +/* return the pending exception (cannot be called twice). */ +JSValue JS_GetException(JSContext *ctx) +{ + JSValue val; + JSRuntime *rt = ctx->rt; + val = rt->current_exception; + rt->current_exception = JS_UNINITIALIZED; + return val; +} + +bool JS_HasException(JSContext *ctx) +{ + return !JS_IsUninitialized(ctx->rt->current_exception); +} + +static void dbuf_put_leb128(DynBuf *s, uint32_t v) +{ + uint32_t a; + for(;;) { + a = v & 0x7f; + v >>= 7; + if (v != 0) { + dbuf_putc(s, a | 0x80); + } else { + dbuf_putc(s, a); + break; + } + } +} + +static void dbuf_put_sleb128(DynBuf *s, int32_t v1) +{ + uint32_t v = v1; + dbuf_put_leb128(s, (2 * v) ^ -(v >> 31)); +} + +static int get_leb128(uint32_t *pval, const uint8_t *buf, + const uint8_t *buf_end) +{ + const uint8_t *ptr = buf; + uint32_t v, a, i; + v = 0; + for(i = 0; i < 5; i++) { + if (unlikely(ptr >= buf_end)) + break; + a = *ptr++; + v |= (a & 0x7f) << (i * 7); + if (!(a & 0x80)) { + *pval = v; + return ptr - buf; + } + } + *pval = 0; + return -1; +} + +static int get_sleb128(int32_t *pval, const uint8_t *buf, + const uint8_t *buf_end) +{ + int ret; + uint32_t val; + ret = get_leb128(&val, buf, buf_end); + if (ret < 0) { + *pval = 0; + return -1; + } + *pval = (val >> 1) ^ -(val & 1); + return ret; +} + +static int find_line_num(JSContext *ctx, JSFunctionBytecode *b, + uint32_t pc_value, int *col) +{ + const uint8_t *p_end, *p; + int new_line_num, new_col_num, line_num, col_num, pc, v, ret; + unsigned int op; + + *col = 1; + p = b->pc2line_buf; + if (!p) + goto fail; + p_end = p + b->pc2line_len; + pc = 0; + line_num = b->line_num; + col_num = b->col_num; + while (p < p_end) { + op = *p++; + if (op == 0) { + uint32_t val; + ret = get_leb128(&val, p, p_end); + if (ret < 0) + goto fail; + pc += val; + p += ret; + ret = get_sleb128(&v, p, p_end); + if (ret < 0) + goto fail; + p += ret; + new_line_num = line_num + v; + } else { + op -= PC2LINE_OP_FIRST; + pc += (op / PC2LINE_RANGE); + new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE; + } + ret = get_sleb128(&v, p, p_end); + if (ret < 0) + goto fail; + p += ret; + new_col_num = col_num + v; + if (pc_value < pc) + break; + line_num = new_line_num; + col_num = new_col_num; + } + *col = col_num; + return line_num; +fail: + /* should never happen */ + return b->line_num; +} + +/* in order to avoid executing arbitrary code during the stack trace + generation, we only look at simple 'name' properties containing a + string. */ +static const char *get_func_name(JSContext *ctx, JSValueConst func) +{ + JSProperty *pr; + JSShapeProperty *prs; + JSValue val; + + if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT) + return NULL; + prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name); + if (!prs) + return NULL; + if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL) + return NULL; + val = pr->u.value; + if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) + return NULL; + return JS_ToCString(ctx, val); +} + +/* Note: it is important that no exception is returned by this function */ +static bool can_add_backtrace(JSValueConst obj) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + return false; + p = JS_VALUE_GET_OBJ(obj); + if (p->class_id != JS_CLASS_ERROR && p->class_id != JS_CLASS_DOM_EXCEPTION) + return false; + if (find_own_property1(p, JS_ATOM_stack)) + return false; + return true; +} + +#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0) +/* only taken into account if filename is provided */ +#define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1) +#define JS_BACKTRACE_FLAG_FILTER_FUNC (1 << 2) + +/* if filename != NULL, an additional level is added with the filename + and line number information (used for parse error). */ +static void build_backtrace(JSContext *ctx, JSValueConst error_val, + JSValueConst filter_func, const char *filename, + int line_num, int col_num, int backtrace_flags) +{ + JSStackFrame *sf, *sf_start; + JSValue stack, prepare, saved_exception; + DynBuf dbuf; + const char *func_name_str; + const char *str1; + JSObject *p; + JSFunctionBytecode *b; + bool backtrace_barrier, has_prepare, has_filter_func; + JSRuntime *rt; + JSCallSiteData csd[64]; + uint32_t i; + double d; + int stack_trace_limit; + + rt = ctx->rt; + if (rt->in_build_stack_trace) + return; + rt->in_build_stack_trace = true; + + // Save exception because conversion to double may fail. + saved_exception = JS_GetException(ctx); + + // Extract stack trace limit. + // Ignore error since it sets d to NAN anyway. + // coverity[check_return] + JS_ToFloat64(ctx, &d, ctx->error_stack_trace_limit); + if (isnan(d) || d < 0.0) + stack_trace_limit = 0; + else if (d > INT32_MAX) + stack_trace_limit = INT32_MAX; + else + stack_trace_limit = fabs(d); + + // Restore current exception. + JS_Throw(ctx, saved_exception); + saved_exception = JS_UNINITIALIZED; + + stack_trace_limit = min_int(stack_trace_limit, countof(csd)); + stack_trace_limit = max_int(stack_trace_limit, 0); + has_prepare = false; + has_filter_func = backtrace_flags & JS_BACKTRACE_FLAG_FILTER_FUNC; + i = 0; + + if (!JS_IsNull(ctx->error_ctor)) { + prepare = js_dup(ctx->error_prepare_stack); + has_prepare = JS_IsFunction(ctx, prepare); + } + + if (has_prepare) { + saved_exception = JS_GetException(ctx); + if (stack_trace_limit == 0) + goto done; + if (filename) + js_new_callsite_data2(ctx, &csd[i++], filename, line_num, col_num); + } else { + js_dbuf_init(ctx, &dbuf); + if (stack_trace_limit == 0) + goto done; + if (filename) { + i++; + dbuf_printf(&dbuf, " at %s", filename); + if (line_num != -1) + dbuf_printf(&dbuf, ":%d:%d", line_num, col_num); + dbuf_putc(&dbuf, '\n'); + } + } + + if (filename && (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)) + goto done; + + sf_start = rt->current_stack_frame; + + /* Find the frame we want to start from. Note that when a filter is used the filter + function will be the first, but we also specify we want to skip the first one. */ + if (has_filter_func) { + for (sf = sf_start; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) { + if (js_same_value(ctx, sf->cur_func, filter_func)) { + sf_start = sf; + break; + } + } + } + + for (sf = sf_start; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) { + if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) { + backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL; + continue; + } + + p = JS_VALUE_GET_OBJ(sf->cur_func); + b = NULL; + backtrace_barrier = false; + + if (js_class_has_bytecode(p->class_id)) { + b = p->u.func.function_bytecode; + backtrace_barrier = b->backtrace_barrier; + } + + if (has_prepare) { + js_new_callsite_data(ctx, &csd[i], sf); + } else { + /* func_name_str is UTF-8 encoded if needed */ + func_name_str = get_func_name(ctx, sf->cur_func); + if (!func_name_str || func_name_str[0] == '\0') + str1 = ""; + else + str1 = func_name_str; + dbuf_printf(&dbuf, " at %s", str1); + JS_FreeCString(ctx, func_name_str); + + if (b && sf->cur_pc) { + const char *atom_str; + int line_num1, col_num1; + uint32_t pc; + + pc = sf->cur_pc - b->byte_code_buf - 1; + line_num1 = find_line_num(ctx, b, pc, &col_num1); + atom_str = b->filename ? JS_AtomToCString(ctx, b->filename) : NULL; + dbuf_printf(&dbuf, " (%s", atom_str ? atom_str : ""); + JS_FreeCString(ctx, atom_str); + if (line_num1 != -1) + dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1); + dbuf_putc(&dbuf, ')'); + } else if (b) { + // FIXME(bnoordhuis) Missing `sf->cur_pc = pc` in bytecode + // handler in JS_CallInternal. Almost never user observable + // except with intercepting JS proxies that throw exceptions. + dbuf_printf(&dbuf, " (missing)"); + } else { + dbuf_printf(&dbuf, " (native)"); + } + dbuf_putc(&dbuf, '\n'); + } + i++; + + /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */ + if (backtrace_barrier) + break; + } + done: + if (has_prepare) { + int j = 0, k; + stack = JS_NewArray(ctx); + if (JS_IsException(stack)) { + stack = JS_NULL; + } else { + for (; j < i; j++) { + JSValue v = js_new_callsite(ctx, &csd[j]); + if (JS_IsException(v)) + break; + if (JS_DefinePropertyValueUint32(ctx, stack, j, v, JS_PROP_C_W_E) < 0) { + JS_FreeValue(ctx, v); + break; + } + } + } + // Clear the csd's we didn't use in case of error. + for (k = j; k < i; k++) { + JS_FreeValue(ctx, csd[k].filename); + JS_FreeValue(ctx, csd[k].func); + JS_FreeValue(ctx, csd[k].func_name); + } + JSValueConst args[] = { + error_val, + stack, + }; + JSValue stack2 = JS_Call(ctx, prepare, ctx->error_ctor, countof(args), args); + JS_FreeValue(ctx, stack); + if (JS_IsException(stack2)) + stack = JS_NULL; + else + stack = stack2; + JS_FreeValue(ctx, prepare); + JS_Throw(ctx, saved_exception); + } else { + if (dbuf_error(&dbuf)) + stack = JS_NULL; + else + stack = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size); + dbuf_free(&dbuf); + } + + if (JS_IsUndefined(ctx->error_back_trace)) + ctx->error_back_trace = js_dup(stack); + if (has_filter_func || can_add_backtrace(error_val)) { + JS_DefinePropertyValue(ctx, error_val, JS_ATOM_stack, stack, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + } else { + JS_FreeValue(ctx, stack); + } + + rt->in_build_stack_trace = false; +} + +JSValue JS_NewError(JSContext *ctx) +{ + JSValue obj = JS_NewObjectClass(ctx, JS_CLASS_ERROR); + if (JS_IsException(obj)) + return JS_EXCEPTION; + build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, 0); + return obj; +} + +static JSValue JS_MakeError2(JSContext *ctx, JSErrorEnum error_num, + bool add_backtrace, const char *message) +{ + JSValue obj, msg; + + if (error_num == JS_PLAIN_ERROR) { + obj = JS_NewObjectClass(ctx, JS_CLASS_ERROR); + } else { + obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num], + JS_CLASS_ERROR); + } + if (JS_IsException(obj)) + return JS_EXCEPTION; + msg = JS_NewString(ctx, message); + if (JS_IsException(msg)) + msg = JS_NewString(ctx, "Invalid error message"); + if (!JS_IsException(msg)) { + JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + } + if (add_backtrace) + build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, 0); + return obj; +} + +static JSValue JS_PRINTF_FORMAT_ATTR(4, 0) +JS_MakeError(JSContext *ctx, JSErrorEnum error_num, bool add_backtrace, + JS_PRINTF_FORMAT const char *fmt, va_list ap) +{ + char buf[256]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + return JS_MakeError2(ctx, error_num, add_backtrace, buf); +} + +/* fmt and arguments may be pure ASCII or UTF-8 encoded contents */ +static JSValue JS_PRINTF_FORMAT_ATTR(4, 0) +JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, bool add_backtrace, + JS_PRINTF_FORMAT const char *fmt, va_list ap) +{ + JSValue obj; + + obj = JS_MakeError(ctx, error_num, add_backtrace, fmt, ap); + if (unlikely(JS_IsException(obj))) { + /* out of memory: throw JS_NULL to avoid recursing */ + obj = JS_NULL; + } + return JS_Throw(ctx, obj); +} + +static JSValue JS_PRINTF_FORMAT_ATTR(3, 0) +JS_ThrowError(JSContext *ctx, JSErrorEnum error_num, + JS_PRINTF_FORMAT const char *fmt, va_list ap) +{ + JSRuntime *rt = ctx->rt; + JSStackFrame *sf; + bool add_backtrace; + + /* the backtrace is added later if called from a bytecode function */ + sf = rt->current_stack_frame; + add_backtrace = !rt->in_out_of_memory && + (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL)); + return JS_ThrowError2(ctx, error_num, add_backtrace, fmt, ap); +} + +#define JS_ERROR_MAP(X) \ + X(Internal, INTERNAL) \ + X(Plain, PLAIN) \ + X(Range, RANGE) \ + X(Reference, REFERENCE) \ + X(Syntax, SYNTAX) \ + X(Type, TYPE) \ + +#define X(lc, uc) \ + JSValue JS_PRINTF_FORMAT_ATTR(2, 3) \ + JS_New##lc##Error(JSContext *ctx, \ + JS_PRINTF_FORMAT const char *fmt, ...) \ + { \ + JSValue val; \ + va_list ap; \ + \ + va_start(ap, fmt); \ + val = JS_MakeError(ctx, JS_##uc##_ERROR, \ + /*add_backtrace*/true, fmt, ap); \ + va_end(ap); \ + return val; \ + } \ + JSValue JS_PRINTF_FORMAT_ATTR(2, 3) \ + JS_Throw##lc##Error(JSContext *ctx, \ + JS_PRINTF_FORMAT const char *fmt, ...) \ + { \ + JSValue val; \ + va_list ap; \ + \ + va_start(ap, fmt); \ + val = JS_ThrowError(ctx, JS_##uc##_ERROR, fmt, ap); \ + va_end(ap); \ + return val; \ + } \ + +JS_ERROR_MAP(X) + +#undef X +#undef JS_ERROR_MAP + +static int JS_PRINTF_FORMAT_ATTR(3, 4) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, JS_PRINTF_FORMAT const char *fmt, ...) +{ + va_list ap; + + if ((flags & JS_PROP_THROW) || + ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { + va_start(ap, fmt); + JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap); + va_end(ap); + return -1; + } else { + return false; + } +} + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif // __GNUC__ +static JSValue JS_ThrowTypeErrorAtom(JSContext *ctx, const char *fmt, JSAtom atom) +{ + char buf[ATOM_GET_STR_BUF_SIZE]; + JS_AtomGetStr(ctx, buf, sizeof(buf), atom); + return JS_ThrowTypeError(ctx, fmt, buf); +} + +static JSValue JS_ThrowSyntaxErrorAtom(JSContext *ctx, const char *fmt, JSAtom atom) +{ + char buf[ATOM_GET_STR_BUF_SIZE]; + JS_AtomGetStr(ctx, buf, sizeof(buf), atom); + return JS_ThrowSyntaxError(ctx, fmt, buf); +} +#ifdef __GNUC__ +#pragma GCC diagnostic pop // ignored "-Wformat-nonliteral" +#endif // __GNUC__ + +static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom) +{ + if ((flags & JS_PROP_THROW) || + ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { + JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom); + return -1; + } else { + return false; + } +} + +int sausage_js_had_oom(JSContext *ctx) +{ + return ctx->rt->sausage_had_out_of_memory; +} + +JSValue JS_ThrowOutOfMemory(JSContext *ctx) +{ + JSRuntime *rt = ctx->rt; + rt->sausage_had_out_of_memory = true; + if (!rt->in_out_of_memory) { + rt->in_out_of_memory = true; + JS_ThrowInternalError(ctx, "out of memory"); + rt->in_out_of_memory = false; + } + return JS_EXCEPTION; +} + +static JSValue JS_ThrowStackOverflow(JSContext *ctx) +{ + return JS_ThrowRangeError(ctx, "Maximum call stack size exceeded"); +} + +static JSValue JS_ThrowTypeErrorNotAConstructor(JSContext *ctx, + JSValueConst func_obj) +{ + JSObject *p; + JSAtom name; + + if (JS_TAG_OBJECT != JS_VALUE_GET_TAG(func_obj)) + goto fini; + p = JS_VALUE_GET_OBJ(func_obj); + if (!js_class_has_bytecode(p->class_id)) + goto fini; + name = p->u.func.function_bytecode->func_name; + if (name == JS_ATOM_NULL) + goto fini; + return JS_ThrowTypeErrorAtom(ctx, "%s is not a constructor", name); +fini: + return JS_ThrowTypeError(ctx, "not a constructor"); +} + +static JSValue JS_ThrowTypeErrorNotAFunction(JSContext *ctx) +{ + return JS_ThrowTypeError(ctx, "not a function"); +} + +static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx) +{ + return JS_ThrowTypeError(ctx, "not an object"); +} + +static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx) +{ + return JS_ThrowTypeError(ctx, "not a symbol"); +} + +static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name) +{ + char buf[ATOM_GET_STR_BUF_SIZE]; + return JS_ThrowReferenceError(ctx, "%s is not defined", + JS_AtomGetStr(ctx, buf, sizeof(buf), name)); +} + +static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name) +{ + char buf[ATOM_GET_STR_BUF_SIZE]; + return JS_ThrowReferenceError(ctx, "%s is not initialized", + name == JS_ATOM_NULL ? "lexical variable" : + JS_AtomGetStr(ctx, buf, sizeof(buf), name)); +} + +static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx, + JSFunctionBytecode *b, + int idx, bool is_ref) +{ + JSAtom atom = JS_ATOM_NULL; + if (is_ref) { + atom = b->closure_var[idx].var_name; + } else { + /* not present if the function is stripped and contains no eval() */ + if (b->vardefs) + atom = b->vardefs[b->arg_count + idx].var_name; + } + return JS_ThrowReferenceErrorUninitialized(ctx, atom); +} + +static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id) +{ + JSRuntime *rt = ctx->rt; + JSAtom name; + name = rt->class_array[class_id].class_name; + return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name); +} + +static void JS_ThrowInterrupted(JSContext *ctx) +{ + JS_ThrowInternalError(ctx, "interrupted"); + JS_SetUncatchableError(ctx, ctx->rt->current_exception); +} + +static no_inline __exception int __js_poll_interrupts(JSContext *ctx) +{ + JSRuntime *rt = ctx->rt; + ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT; + if (rt->interrupt_handler) { + if (rt->interrupt_handler(rt, rt->interrupt_opaque)) { + JS_ThrowInterrupted(ctx); + return -1; + } + } + return 0; +} + +static inline __exception int js_poll_interrupts(JSContext *ctx) +{ + if (unlikely(--ctx->interrupt_counter <= 0)) { + return __js_poll_interrupts(ctx); + } else { + return 0; + } +} + +/* return -1 (exception) or true/false */ +static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, + JSValueConst proto_val, bool throw_flag) +{ + JSObject *proto, *p, *p1; + JSShape *sh; + + if (throw_flag) { + if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL || + JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED) + goto not_obj; + } else { + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + goto not_obj; + } + p = JS_VALUE_GET_OBJ(obj); + if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) { + if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) { + not_obj: + JS_ThrowTypeErrorNotAnObject(ctx); + return -1; + } + proto = NULL; + } else { + proto = JS_VALUE_GET_OBJ(proto_val); + } + + if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + return true; + + if (unlikely(p->class_id == JS_CLASS_PROXY)) + return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag); + sh = p->shape; + if (sh->proto == proto) + return true; + if (p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_OBJECT])) { + if (throw_flag) { + JS_ThrowTypeError(ctx, "'Immutable prototype object \'Object.prototype\' cannot have their prototype set'"); + return -1; + } + return false; + } + if (!p->extensible) { + if (throw_flag) { + JS_ThrowTypeError(ctx, "object is not extensible"); + return -1; + } else { + return false; + } + } + if (proto) { + /* check if there is a cycle */ + p1 = proto; + do { + if (p1 == p) { + if (throw_flag) { + JS_ThrowTypeError(ctx, "circular prototype chain"); + return -1; + } else { + return false; + } + } + /* Note: for Proxy objects, proto is NULL */ + p1 = p1->shape->proto; + } while (p1 != NULL); + js_dup(proto_val); + } + + if (js_shape_prepare_update(ctx, p, NULL)) + return -1; + sh = p->shape; + if (sh->proto) + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); + sh->proto = proto; + return true; +} + +/* return -1 (exception) or true/false */ +int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val) +{ + return JS_SetPrototypeInternal(ctx, obj, proto_val, true); +} + +/* Only works for primitive types, otherwise return JS_NULL. */ +static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val) +{ + JSValue ret; + switch(JS_VALUE_GET_NORM_TAG(val)) { + case JS_TAG_SHORT_BIG_INT: + case JS_TAG_BIG_INT: + ret = ctx->class_proto[JS_CLASS_BIG_INT]; + break; + case JS_TAG_INT: + case JS_TAG_FLOAT64: + ret = ctx->class_proto[JS_CLASS_NUMBER]; + break; + case JS_TAG_BOOL: + ret = ctx->class_proto[JS_CLASS_BOOLEAN]; + break; + case JS_TAG_STRING: + ret = ctx->class_proto[JS_CLASS_STRING]; + break; + case JS_TAG_SYMBOL: + ret = ctx->class_proto[JS_CLASS_SYMBOL]; + break; + case JS_TAG_OBJECT: + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + default: + ret = JS_NULL; + break; + } + return ret; +} + +/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */ +JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj) +{ + JSValue val; + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { + JSObject *p; + p = JS_VALUE_GET_OBJ(obj); + if (unlikely(p->class_id == JS_CLASS_PROXY)) { + val = js_proxy_getPrototypeOf(ctx, obj); + } else { + p = p->shape->proto; + if (!p) + val = JS_NULL; + else + val = js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); + } + } else { + val = js_dup(JS_GetPrototypePrimitive(ctx, obj)); + } + return val; +} + +static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj) +{ + JSValue obj1; + obj1 = JS_GetPrototype(ctx, obj); + JS_FreeValue(ctx, obj); + return obj1; +} + +int JS_GetLength(JSContext *ctx, JSValueConst obj, int64_t *pres) { + return js_get_length64(ctx, pres, obj); +} + +int JS_SetLength(JSContext *ctx, JSValueConst obj, int64_t len) { + return js_set_length64(ctx, obj, len); +} + +/* return true, false or (-1) in case of exception */ +static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, + JSValueConst obj) +{ + JSValue obj_proto; + JSObject *proto; + const JSObject *p, *proto1; + int ret; + + if (!JS_IsFunction(ctx, obj)) + return false; + p = JS_VALUE_GET_OBJ(obj); + if (p->class_id == JS_CLASS_BOUND_FUNCTION) { + JSBoundFunction *s = p->u.bound_function; + return JS_IsInstanceOf(ctx, val, s->func_obj); + } + + /* Only explicitly boxed values are instances of constructors */ + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return false; + obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype); + if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) { + if (!JS_IsException(obj_proto)) + JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object"); + ret = -1; + goto done; + } + proto = JS_VALUE_GET_OBJ(obj_proto); + p = JS_VALUE_GET_OBJ(val); + for(;;) { + proto1 = p->shape->proto; + if (!proto1) { + /* slow case if proxy in the prototype chain */ + if (unlikely(p->class_id == JS_CLASS_PROXY)) { + JSValue obj1; + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p)); + for(;;) { + obj1 = JS_GetPrototypeFree(ctx, obj1); + if (JS_IsException(obj1)) { + ret = -1; + break; + } + if (JS_IsNull(obj1)) { + ret = false; + break; + } + if (proto == JS_VALUE_GET_OBJ(obj1)) { + JS_FreeValue(ctx, obj1); + ret = true; + break; + } + /* must check for timeout to avoid infinite loop */ + if (js_poll_interrupts(ctx)) { + JS_FreeValue(ctx, obj1); + ret = -1; + break; + } + } + } else { + ret = false; + } + break; + } + p = proto1; + if (proto == p) { + ret = true; + break; + } + } +done: + JS_FreeValue(ctx, obj_proto); + return ret; +} + +/* return true, false or (-1) in case of exception */ +int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj) +{ + JSValue method; + + if (!JS_IsObject(obj)) + goto fail; + method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance); + if (JS_IsException(method)) + return -1; + if (!JS_IsNull(method) && !JS_IsUndefined(method)) { + JSValue ret; + ret = JS_CallFree(ctx, method, obj, 1, &val); + return JS_ToBoolFree(ctx, ret); + } + + /* legacy case */ + if (!JS_IsFunction(ctx, obj)) { + fail: + JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand"); + return -1; + } + return JS_OrdinaryIsInstanceOf(ctx, val, obj); +} + +#include "builtin-array-fromasync.h" + +static JSValue js_bytecode_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, + void *opaque) +{ + switch ((uintptr_t)opaque) { + default: + abort(); + case JS_BUILTIN_ARRAY_FROMASYNC: + { + JSValue obj = JS_ReadObject(ctx, qjsc_builtin_array_fromasync, + sizeof(qjsc_builtin_array_fromasync), + JS_READ_OBJ_BYTECODE); + if (JS_IsException(obj)) + return JS_EXCEPTION; + JSValue fun = JS_EvalFunction(ctx, obj); + if (JS_IsException(fun)) + return JS_EXCEPTION; + assert(JS_IsFunction(ctx, fun)); + JSValue args[] = { + JS_NewCFunction(ctx, js_array_constructor, "Array", 0), + JS_NewCFunctionMagic(ctx, js_error_constructor, "TypeError", 1, + JS_CFUNC_constructor_or_func_magic, + JS_TYPE_ERROR), + JS_AtomToValue(ctx, JS_ATOM_Symbol_asyncIterator), + JS_NewCFunctionMagic(ctx, js_object_defineProperty, + "Object.defineProperty", 3, + JS_CFUNC_generic_magic, 0), + JS_AtomToValue(ctx, JS_ATOM_Symbol_iterator), + }; + JSValue result = JS_Call(ctx, fun, JS_UNDEFINED, + countof(args), vc(args)); + for (size_t i = 0; i < countof(args); i++) + JS_FreeValue(ctx, args[i]); + JS_FreeValue(ctx, fun); + if (JS_SetPrototypeInternal(ctx, result, ctx->function_proto, + /*throw_flag*/true) < 0) { + JS_FreeValue(ctx, result); + return JS_EXCEPTION; + } + return result; + } + } + return JS_UNDEFINED; +} + +/* return the value associated to the autoinit property or an exception */ +typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); + +static JSAutoInitFunc *const js_autoinit_func_table[] = { + js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */ + js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */ + JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */ + js_bytecode_autoinit, /* JS_AUTOINIT_ID_BYTECODE */ +}; + +/* warning: 'prs' is reallocated after it */ +static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, + JSProperty *pr, JSShapeProperty *prs) +{ + JSValue val; + JSContext *realm; + JSAutoInitFunc *func; + + if (js_shape_prepare_update(ctx, p, &prs)) + return -1; + + realm = js_autoinit_get_realm(pr); + func = js_autoinit_func_table[js_autoinit_get_id(pr)]; + /* 'func' shall not modify the object properties 'pr' */ + val = func(realm, p, prop, pr->u.init.opaque); + js_autoinit_free(ctx->rt, pr); + prs->flags &= ~JS_PROP_TMASK; + pr->u.value = JS_UNDEFINED; + if (JS_IsException(val)) + return -1; + pr->u.value = val; + return 0; +} + +static JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, + JSAtom prop, JSValueConst this_obj, + bool throw_ref_error) +{ + JSObject *p; + JSProperty *pr; + JSShapeProperty *prs; + uint32_t tag; + + tag = JS_VALUE_GET_TAG(obj); + if (unlikely(tag != JS_TAG_OBJECT)) { + switch(tag) { + case JS_TAG_NULL: + return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop); + case JS_TAG_UNDEFINED: + return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop); + case JS_TAG_EXCEPTION: + return JS_EXCEPTION; + case JS_TAG_STRING: + { + JSString *p1 = JS_VALUE_GET_STRING(obj); + if (__JS_AtomIsTaggedInt(prop)) { + uint32_t idx, ch; + idx = __JS_AtomToUInt32(prop); + if (idx < p1->len) { + ch = string_get(p1, idx); + return js_new_string_char(ctx, ch); + } + } else if (prop == JS_ATOM_length) { + return js_int32(p1->len); + } + } + break; + default: + break; + } + /* cannot raise an exception */ + p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj)); + if (!p) + return JS_UNDEFINED; + } else { + p = JS_VALUE_GET_OBJ(obj); + } + + for(;;) { + prs = find_own_property(&pr, p, prop); + if (prs) { + /* found */ + if (unlikely(prs->flags & JS_PROP_TMASK)) { + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { + if (unlikely(!pr->u.getset.getter)) { + return JS_UNDEFINED; + } else { + JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter); + /* Note: the field could be removed in the getter */ + func = js_dup(func); + return JS_CallFree(ctx, func, this_obj, 0, NULL); + } + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + JSValue val = *pr->u.var_ref->pvalue; + if (unlikely(JS_IsUninitialized(val))) + return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); + return js_dup(val); + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + /* Instantiate property and retry */ + if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) + return JS_EXCEPTION; + continue; + } + } else { + return js_dup(pr->u.value); + } + } + if (unlikely(p->is_exotic)) { + /* exotic behaviors */ + if (p->fast_array) { + if (__JS_AtomIsTaggedInt(prop)) { + uint32_t idx = __JS_AtomToUInt32(prop); + if (idx < p->u.array.count) { + /* we avoid duplicating the code */ + return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); + } else if (is_typed_array(p->class_id)) { + return JS_UNDEFINED; + } + } else if (is_typed_array(p->class_id)) { + int ret; + ret = JS_AtomIsNumericIndex(ctx, prop); + if (ret != 0) { + if (ret < 0) + return JS_EXCEPTION; + return JS_UNDEFINED; + } + } + } else { + const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; + if (em) { + if (em->get_property) { + JSValue obj1, retval; + /* XXX: should pass throw_ref_error */ + /* Note: if 'p' is a prototype, it can be + freed in the called function */ + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); + retval = em->get_property(ctx, obj1, prop, this_obj); + JS_FreeValue(ctx, obj1); + return retval; + } + if (em->get_own_property) { + JSPropertyDescriptor desc; + int ret; + JSValue obj1; + + /* Note: if 'p' is a prototype, it can be + freed in the called function */ + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); + ret = em->get_own_property(ctx, &desc, obj1, prop); + JS_FreeValue(ctx, obj1); + if (ret < 0) + return JS_EXCEPTION; + if (ret) { + if (desc.flags & JS_PROP_GETSET) { + JS_FreeValue(ctx, desc.setter); + return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL); + } else { + return desc.value; + } + } + } + } + } + } + p = p->shape->proto; + if (!p) + break; + } + if (unlikely(throw_ref_error)) { + return JS_ThrowReferenceErrorNotDefined(ctx, prop); + } else { + return JS_UNDEFINED; + } +} + +JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop) +{ + return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, false); +} + +static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) +{ + return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist", + atom); +} + +/* Private fields can be added even on non extensible objects or + Proxies */ +static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj, + JSValue name, JSValue val) +{ + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + JSAtom prop; + + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { + JS_ThrowTypeErrorNotAnObject(ctx); + goto fail; + } + /* safety check */ + if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) { + JS_ThrowTypeErrorNotASymbol(ctx); + goto fail; + } + prop = js_symbol_to_atom(ctx, name); + p = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p, prop); + if (prs) { + JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists", + prop); + goto fail; + } + pr = add_property(ctx, p, prop, JS_PROP_C_W_E); + if (unlikely(!pr)) { + fail: + JS_FreeValue(ctx, val); + return -1; + } + pr->u.value = val; + return 0; +} + +static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj, + JSValueConst name) +{ + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + JSAtom prop; + + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) + return JS_ThrowTypeErrorNotAnObject(ctx); + /* safety check */ + if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) + return JS_ThrowTypeErrorNotASymbol(ctx); + prop = js_symbol_to_atom(ctx, name); + p = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p, prop); + if (!prs) { + JS_ThrowTypeErrorPrivateNotFound(ctx, prop); + return JS_EXCEPTION; + } + return js_dup(pr->u.value); +} + +static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj, + JSValueConst name, JSValue val) +{ + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + JSAtom prop; + + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { + JS_ThrowTypeErrorNotAnObject(ctx); + goto fail; + } + /* safety check */ + if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) { + JS_ThrowTypeErrorNotASymbol(ctx); + goto fail; + } + prop = js_symbol_to_atom(ctx, name); + p = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p, prop); + if (!prs) { + JS_ThrowTypeErrorPrivateNotFound(ctx, prop); + fail: + JS_FreeValue(ctx, val); + return -1; + } + set_value(ctx, &pr->u.value, val); + return 0; +} + +/* add a private brand field to 'home_obj' if not already present and + if obj is != null add a private brand to it */ +static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) +{ + JSObject *p, *p1; + JSShapeProperty *prs; + JSProperty *pr; + JSValue brand; + JSAtom brand_atom; + + if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) { + JS_ThrowTypeErrorNotAnObject(ctx); + return -1; + } + p = JS_VALUE_GET_OBJ(home_obj); + prs = find_own_property(&pr, p, JS_ATOM_Private_brand); + if (!prs) { + /* if the brand is not present, add it */ + brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE); + if (JS_IsException(brand)) + return -1; + pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E); + if (!pr) { + JS_FreeValue(ctx, brand); + return -1; + } + pr->u.value = js_dup(brand); + } else { + brand = js_dup(pr->u.value); + } + brand_atom = js_symbol_to_atom(ctx, brand); + + if (JS_IsObject(obj)) { + p1 = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p1, brand_atom); + if (unlikely(prs)) { + JS_FreeAtom(ctx, brand_atom); + JS_ThrowTypeError(ctx, "private method is already present"); + return -1; + } + pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E); + JS_FreeAtom(ctx, brand_atom); + if (!pr) + return -1; + pr->u.value = JS_UNDEFINED; + } else { + JS_FreeAtom(ctx, brand_atom); + } + + return 0; +} + +/* return a boolean telling if the brand of the home object of 'func' + is present on 'obj' or -1 in case of exception */ +static int JS_CheckBrand(JSContext *ctx, JSValue obj, JSValue func) +{ + JSObject *p, *p1, *home_obj; + JSShapeProperty *prs; + JSProperty *pr; + JSValue brand; + + /* get the home object of 'func' */ + if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) + goto not_obj; + p1 = JS_VALUE_GET_OBJ(func); + if (!js_class_has_bytecode(p1->class_id)) + goto not_obj; + home_obj = p1->u.func.home_object; + if (!home_obj) + goto not_obj; + prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand); + if (!prs) { + JS_ThrowTypeError(ctx, "expecting private field"); + return -1; + } + brand = pr->u.value; + /* safety check */ + if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL)) + goto not_obj; + + /* get the brand array of 'obj' */ + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { + not_obj: + JS_ThrowTypeErrorNotAnObject(ctx); + return -1; + } + p = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, brand)); + return (prs != NULL); +} + +static uint32_t js_string_obj_get_length(JSContext *ctx, JSValueConst obj) +{ + JSObject *p; + JSString *p1; + uint32_t len = 0; + + /* This is a class exotic method: obj class_id is JS_CLASS_STRING */ + p = JS_VALUE_GET_OBJ(obj); + if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) { + p1 = JS_VALUE_GET_STRING(p->u.object_data); + len = p1->len; + } + return len; +} + +static int num_keys_cmp(const void *p1, const void *p2, void *opaque) +{ + JSContext *ctx = opaque; + JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom; + JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom; + uint32_t v1, v2; + bool atom1_is_integer, atom2_is_integer; + + atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1); + atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2); + assert(atom1_is_integer && atom2_is_integer); + if (v1 < v2) + return -1; + else if (v1 == v2) + return 0; + else + return 1; +} + +static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len) +{ + uint32_t i; + if (tab) { + for(i = 0; i < len; i++) + JS_FreeAtom(ctx, tab[i].atom); + js_free(ctx, tab); + } +} + +/* return < 0 in case if exception, 0 if OK. ptab and its atoms must + be freed by the user. */ +static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, + JSPropertyEnum **ptab, + uint32_t *plen, + JSObject *p, int flags) +{ + int i, j; + JSShape *sh; + JSShapeProperty *prs; + JSPropertyEnum *tab_atom, *tab_exotic; + JSAtom atom; + uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count; + uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count; + bool is_enumerable, num_sorted; + uint32_t num_key; + JSAtomKindEnum kind; + + /* clear pointer for consistency in case of failure */ + *ptab = NULL; + *plen = 0; + + /* compute the number of returned properties */ + num_keys_count = 0; + str_keys_count = 0; + sym_keys_count = 0; + exotic_keys_count = 0; + exotic_count = 0; + tab_exotic = NULL; + sh = p->shape; + for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { + atom = prs->atom; + if (atom != JS_ATOM_NULL) { + is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0); + kind = JS_AtomGetKind(ctx, atom); + if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && + ((flags >> kind) & 1) != 0) { + /* need to raise an exception in case of the module + name space (implicit GetOwnProperty) */ + if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) && + (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) { + JSVarRef *var_ref = p->prop[i].u.var_ref; + if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) { + JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); + return -1; + } + } + if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { + num_keys_count++; + } else if (kind == JS_ATOM_KIND_STRING) { + str_keys_count++; + } else { + sym_keys_count++; + } + } + } + } + + if (p->is_exotic) { + if (p->fast_array) { + if (flags & JS_GPN_STRING_MASK) { + num_keys_count += p->u.array.count; + } + } else if (p->class_id == JS_CLASS_STRING) { + if (flags & JS_GPN_STRING_MASK) { + num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + } + } else { + const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; + if (em && em->get_own_property_names) { + if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count, + JS_MKPTR(JS_TAG_OBJECT, p))) + return -1; + for(i = 0; i < exotic_count; i++) { + atom = tab_exotic[i].atom; + kind = JS_AtomGetKind(ctx, atom); + if (((flags >> kind) & 1) != 0) { + is_enumerable = false; + if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) { + JSPropertyDescriptor desc; + int res; + /* set the "is_enumerable" field if necessary */ + res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom); + if (res < 0) { + js_free_prop_enum(ctx, tab_exotic, exotic_count); + return -1; + } + if (res) { + is_enumerable = + ((desc.flags & JS_PROP_ENUMERABLE) != 0); + js_free_desc(ctx, &desc); + } + tab_exotic[i].is_enumerable = is_enumerable; + } + if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) { + exotic_keys_count++; + } + } + } + } + } + } + + /* fill them */ + + atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count; + /* avoid allocating 0 bytes */ + tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1)); + if (!tab_atom) { + js_free_prop_enum(ctx, tab_exotic, exotic_count); + return -1; + } + + num_index = 0; + str_index = num_keys_count; + sym_index = str_index + str_keys_count; + + num_sorted = true; + sh = p->shape; + for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { + atom = prs->atom; + if (atom != JS_ATOM_NULL) { + is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0); + kind = JS_AtomGetKind(ctx, atom); + if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && + ((flags >> kind) & 1) != 0) { + if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { + j = num_index++; + num_sorted = false; + } else if (kind == JS_ATOM_KIND_STRING) { + j = str_index++; + } else { + j = sym_index++; + } + tab_atom[j].atom = JS_DupAtom(ctx, atom); + tab_atom[j].is_enumerable = is_enumerable; + } + } + } + + if (p->is_exotic) { + int len; + if (p->fast_array) { + if (flags & JS_GPN_STRING_MASK) { + len = p->u.array.count; + goto add_array_keys; + } + } else if (p->class_id == JS_CLASS_STRING) { + if (flags & JS_GPN_STRING_MASK) { + len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + add_array_keys: + for(i = 0; i < len; i++) { + tab_atom[num_index].atom = __JS_AtomFromUInt32(i); + if (tab_atom[num_index].atom == JS_ATOM_NULL) { + js_free_prop_enum(ctx, tab_atom, num_index); + return -1; + } + tab_atom[num_index].is_enumerable = true; + num_index++; + } + } + } else { + /* Note: exotic keys are not reordered and comes after the object own properties. */ + for(i = 0; i < exotic_count; i++) { + atom = tab_exotic[i].atom; + is_enumerable = tab_exotic[i].is_enumerable; + kind = JS_AtomGetKind(ctx, atom); + if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && + ((flags >> kind) & 1) != 0) { + tab_atom[sym_index].atom = atom; + tab_atom[sym_index].is_enumerable = is_enumerable; + sym_index++; + } else { + JS_FreeAtom(ctx, atom); + } + } + js_free(ctx, tab_exotic); + } + } + + assert(num_index == num_keys_count); + assert(str_index == num_keys_count + str_keys_count); + assert(sym_index == atom_count); + + if (num_keys_count != 0 && !num_sorted) { + rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp, + ctx); + } + *ptab = tab_atom; + *plen = atom_count; + return 0; +} + +int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, + uint32_t *plen, JSValueConst obj, int flags) +{ + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { + JS_ThrowTypeErrorNotAnObject(ctx); + return -1; + } + return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen, + JS_VALUE_GET_OBJ(obj), flags); +} + +/* Return -1 if exception, + false if the property does not exist, true if it exists. If true is + returned, the property descriptor 'desc' is filled present. */ +static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, + JSObject *p, JSAtom prop) +{ + JSShapeProperty *prs; + JSProperty *pr; + +retry: + prs = find_own_property(&pr, p, prop); + if (prs) { + if (desc) { + desc->flags = prs->flags & JS_PROP_C_W_E; + desc->getter = JS_UNDEFINED; + desc->setter = JS_UNDEFINED; + desc->value = JS_UNDEFINED; + if (unlikely(prs->flags & JS_PROP_TMASK)) { + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { + desc->flags |= JS_PROP_GETSET; + if (pr->u.getset.getter) + desc->getter = js_dup(JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); + if (pr->u.getset.setter) + desc->setter = js_dup(JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + JSValue val = *pr->u.var_ref->pvalue; + if (unlikely(JS_IsUninitialized(val))) { + JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); + return -1; + } + desc->value = js_dup(val); + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + /* Instantiate property and retry */ + if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) + return -1; + goto retry; + } + } else { + desc->value = js_dup(pr->u.value); + } + } else { + /* for consistency, send the exception even if desc is NULL */ + if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) { + if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) { + JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); + return -1; + } + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + /* nothing to do: delay instantiation until actual value and/or attributes are read */ + } + } + return true; + } + if (p->is_exotic) { + if (p->fast_array) { + /* specific case for fast arrays */ + if (__JS_AtomIsTaggedInt(prop)) { + uint32_t idx; + idx = __JS_AtomToUInt32(prop); + if (idx < p->u.array.count) { + if (desc) { + desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE | + JS_PROP_CONFIGURABLE; + desc->getter = JS_UNDEFINED; + desc->setter = JS_UNDEFINED; + desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); + } + return true; + } + } + } else { + const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; + if (em && em->get_own_property) { + return em->get_own_property(ctx, desc, + JS_MKPTR(JS_TAG_OBJECT, p), prop); + } + } + } + return false; +} + +int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, + JSValueConst obj, JSAtom prop) +{ + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { + JS_ThrowTypeErrorNotAnObject(ctx); + return -1; + } + return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop); +} + +void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, + uint32_t len) +{ + js_free_prop_enum(ctx, tab, len); +} + +/* return -1 if exception (Proxy object only) or true/false */ +int JS_IsExtensible(JSContext *ctx, JSValueConst obj) +{ + JSObject *p; + + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) + return false; + p = JS_VALUE_GET_OBJ(obj); + if (unlikely(p->class_id == JS_CLASS_PROXY)) + return js_proxy_isExtensible(ctx, obj); + else + return p->extensible; +} + +/* return -1 if exception (Proxy object only) or true/false */ +int JS_PreventExtensions(JSContext *ctx, JSValueConst obj) +{ + JSObject *p; + + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) + return false; + p = JS_VALUE_GET_OBJ(obj); + if (unlikely(p->class_id == JS_CLASS_PROXY)) + return js_proxy_preventExtensions(ctx, obj); + p->extensible = false; + return true; +} + +/* return -1 if exception otherwise true or false */ +int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) +{ + JSObject *p; + int ret; + JSValue obj1; + + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) + return false; + p = JS_VALUE_GET_OBJ(obj); + for(;;) { + if (p->is_exotic) { + const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; + if (em && em->has_property) { + /* has_property can free the prototype */ + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); + ret = em->has_property(ctx, obj1, prop); + JS_FreeValue(ctx, obj1); + return ret; + } + } + /* JS_GetOwnPropertyInternal can free the prototype */ + js_dup(JS_MKPTR(JS_TAG_OBJECT, p)); + ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop); + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + if (ret != 0) + return ret; + if (is_typed_array(p->class_id)) { + ret = JS_AtomIsNumericIndex(ctx, prop); + if (ret != 0) { + if (ret < 0) + return -1; + return false; + } + } + p = p->shape->proto; + if (!p) + break; + } + return false; +} + +/* val must be a symbol */ +static JSAtom js_symbol_to_atom(JSContext *ctx, JSValueConst val) +{ + JSAtomStruct *p = JS_VALUE_GET_PTR(val); + return js_get_atom_index(ctx->rt, p); +} + +/* return JS_ATOM_NULL in case of exception */ +static JSAtom JS_ValueToAtomInternal(JSContext *ctx, JSValueConst val, + int flags) +{ + JSAtom atom; + uint32_t tag; + tag = JS_VALUE_GET_TAG(val); + if (tag == JS_TAG_INT && + (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) { + /* fast path for integer values */ + atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val)); + } else if (tag == JS_TAG_SYMBOL) { + JSAtomStruct *p = JS_VALUE_GET_PTR(val); + atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p)); + } else { + JSValue str; + str = JS_ToPropertyKeyInternal(ctx, val, flags); + if (JS_IsException(str)) + return JS_ATOM_NULL; + if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) { + atom = js_symbol_to_atom(ctx, str); + } else { + atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str)); + } + } + return atom; +} + +JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val) +{ + return JS_ValueToAtomInternal(ctx, val, /*flags*/0); +} + +static bool js_get_fast_array_element(JSContext *ctx, JSObject *p, + uint32_t idx, JSValue *pval) +{ + switch(p->class_id) { + case JS_CLASS_ARRAY: + case JS_CLASS_ARGUMENTS: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_dup(p->u.array.u.values[idx]); + return true; + case JS_CLASS_INT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.int8_ptr[idx]); + return true; + case JS_CLASS_UINT8C_ARRAY: + case JS_CLASS_UINT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.uint8_ptr[idx]); + return true; + case JS_CLASS_INT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.int16_ptr[idx]); + return true; + case JS_CLASS_UINT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.uint16_ptr[idx]); + return true; + case JS_CLASS_INT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_int32(p->u.array.u.int32_ptr[idx]); + return true; + case JS_CLASS_UINT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_uint32(p->u.array.u.uint32_ptr[idx]); + return true; + case JS_CLASS_BIG_INT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); + return true; + case JS_CLASS_BIG_UINT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); + return true; + case JS_CLASS_FLOAT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_float64(fromfp16(p->u.array.u.fp16_ptr[idx])); + return true; + case JS_CLASS_FLOAT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_float64(p->u.array.u.float_ptr[idx]); + return true; + case JS_CLASS_FLOAT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) return false; + *pval = js_float64(p->u.array.u.double_ptr[idx]); + return true; + default: + return false; + } +} + +static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj, + JSValue prop) +{ + JSAtom atom; + JSValue ret; + uint32_t tag; + + tag = JS_VALUE_GET_TAG(this_obj); + if (likely(tag == JS_TAG_OBJECT)) { + if (JS_VALUE_GET_TAG(prop) == JS_TAG_INT) { + JSObject *p = JS_VALUE_GET_OBJ(this_obj); + uint32_t idx = JS_VALUE_GET_INT(prop); + JSValue val; + /* fast path for array and typed array access */ + if (js_get_fast_array_element(ctx, p, idx, &val)) + return val; + } + } else if (unlikely(tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)) { + // per spec: not allowed to call ToPropertyKey before ToObject + // so we must ensure to not invoke JS anything that's observable + // from JS code + atom = JS_ValueToAtomInternal(ctx, prop, JS_TO_STRING_NO_SIDE_EFFECTS); + JS_FreeValue(ctx, prop); + if (unlikely(atom == JS_ATOM_NULL)) + return JS_EXCEPTION; + if (tag == JS_TAG_NULL) { + JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", atom); + } else { + JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", atom); + } + JS_FreeAtom(ctx, atom); + return JS_EXCEPTION; + } + atom = JS_ValueToAtom(ctx, prop); + JS_FreeValue(ctx, prop); + if (unlikely(atom == JS_ATOM_NULL)) + return JS_EXCEPTION; + ret = JS_GetProperty(ctx, this_obj, atom); + JS_FreeAtom(ctx, atom); + return ret; +} + +JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, + uint32_t idx) +{ + return JS_GetPropertyInt64(ctx, this_obj, idx); +} + +/* Check if an object has a generalized numeric property. Return value: + -1 for exception, *pval set to JS_EXCEPTION + true if property exists, stored into *pval, + false if property does not exist. *pval set to JS_UNDEFINED. + */ +static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval) +{ + JSValue val; + JSAtom prop; + int present; + + if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT && + (uint64_t)idx <= INT32_MAX)) { + /* fast path for array and typed array access */ + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (js_get_fast_array_element(ctx, p, idx, pval)) + return true; + } + val = JS_EXCEPTION; + present = -1; + prop = JS_NewAtomInt64(ctx, idx); + if (likely(prop != JS_ATOM_NULL)) { + present = JS_HasProperty(ctx, obj, prop); + if (present > 0) { + val = JS_GetProperty(ctx, obj, prop); + if (unlikely(JS_IsException(val))) + present = -1; + } else if (present == false) { + val = JS_UNDEFINED; + } + JS_FreeAtom(ctx, prop); + } + *pval = val; + return present; +} + +JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx) +{ + JSAtom prop; + JSValue val; + + if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT && + (uint64_t)idx <= INT32_MAX)) { + /* fast path for array and typed array access */ + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (js_get_fast_array_element(ctx, p, idx, &val)) + return val; + } + prop = JS_NewAtomInt64(ctx, idx); + if (prop == JS_ATOM_NULL) + return JS_EXCEPTION; + + val = JS_GetProperty(ctx, obj, prop); + JS_FreeAtom(ctx, prop); + return val; +} + +/* `prop` may be pure ASCII or UTF-8 encoded */ +JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, + const char *prop) +{ + JSAtom atom; + JSValue ret; + atom = JS_NewAtom(ctx, prop); + if (atom == JS_ATOM_NULL) + return JS_EXCEPTION; + ret = JS_GetProperty(ctx, this_obj, atom); + JS_FreeAtom(ctx, atom); + return ret; +} + +/* Note: the property value is not initialized. Return NULL if memory + error. */ +static JSProperty *add_property(JSContext *ctx, + JSObject *p, JSAtom prop, int prop_flags) +{ + JSShape *sh, *new_sh; + + sh = p->shape; + if (sh->is_hashed) { + /* try to find an existing shape */ + new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags); + if (new_sh) { + /* matching shape found: use it */ + /* the property array may need to be resized */ + if (new_sh->prop_size != sh->prop_size) { + JSProperty *new_prop; + new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) * + new_sh->prop_size); + if (!new_prop) + return NULL; + p->prop = new_prop; + } + p->shape = js_dup_shape(new_sh); + js_free_shape(ctx->rt, sh); + return &p->prop[new_sh->prop_count - 1]; + } else if (sh->header.ref_count != 1) { + /* if the shape is shared, clone it */ + new_sh = js_clone_shape(ctx, sh); + if (!new_sh) + return NULL; + /* hash the cloned shape */ + new_sh->is_hashed = true; + js_shape_hash_link(ctx->rt, new_sh); + js_free_shape(ctx->rt, p->shape); + p->shape = new_sh; + } + } + assert(p->shape->header.ref_count == 1); + if (add_shape_property(ctx, &p->shape, p, prop, prop_flags)) + return NULL; + return &p->prop[p->shape->prop_count - 1]; +} + +/* can be called on Array or Arguments objects. return < 0 if + memory alloc error. */ +static no_inline __exception int convert_fast_array_to_array(JSContext *ctx, + JSObject *p) +{ + JSProperty *pr; + JSShape *sh; + JSValue *tab; + uint32_t i, len, new_count; + + if (js_shape_prepare_update(ctx, p, NULL)) + return -1; + len = p->u.array.count; + /* resize the properties once to simplify the error handling */ + sh = p->shape; + new_count = sh->prop_count + len; + if (new_count > sh->prop_size) { + if (resize_properties(ctx, &p->shape, p, new_count)) + return -1; + } + + tab = p->u.array.u.values; + for(i = 0; i < len; i++) { + /* add_property cannot fail here but + __JS_AtomFromUInt32(i) fails for i > INT32_MAX */ + pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E); + pr->u.value = *tab++; + } + js_free(ctx, p->u.array.u.values); + p->u.array.count = 0; + p->u.array.u.values = NULL; /* fail safe */ + p->u.array.u1.size = 0; + p->fast_array = 0; + return 0; +} + +static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) +{ + JSShape *sh; + JSShapeProperty *pr, *lpr, *prop; + JSProperty *pr1; + uint32_t lpr_idx; + intptr_t h, h1; + + redo: + sh = p->shape; + h1 = atom & sh->prop_hash_mask; + h = prop_hash_end(sh)[-h1 - 1]; + prop = get_shape_prop(sh); + lpr = NULL; + lpr_idx = 0; /* prevent warning */ + while (h != 0) { + pr = &prop[h - 1]; + if (likely(pr->atom == atom)) { + /* found ! */ + if (!(pr->flags & JS_PROP_CONFIGURABLE)) + return false; + /* realloc the shape if needed */ + if (lpr) + lpr_idx = lpr - get_shape_prop(sh); + if (js_shape_prepare_update(ctx, p, &pr)) + return -1; + sh = p->shape; + /* remove property */ + if (lpr) { + lpr = get_shape_prop(sh) + lpr_idx; + lpr->hash_next = pr->hash_next; + } else { + prop_hash_end(sh)[-h1 - 1] = pr->hash_next; + } + sh->deleted_prop_count++; + /* free the entry */ + pr1 = &p->prop[h - 1]; + free_property(ctx->rt, pr1, pr->flags); + JS_FreeAtom(ctx, pr->atom); + /* put default values */ + pr->flags = 0; + pr->atom = JS_ATOM_NULL; + pr1->u.value = JS_UNDEFINED; + + /* compact the properties if too many deleted properties */ + if (sh->deleted_prop_count >= 8 && + sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) { + compact_properties(ctx, p); + } + return true; + } + lpr = pr; + h = pr->hash_next; + } + + if (p->is_exotic) { + if (p->fast_array) { + uint32_t idx; + if (JS_AtomIsArrayIndex(ctx, &idx, atom) && + idx < p->u.array.count) { + if (p->class_id == JS_CLASS_ARRAY || + p->class_id == JS_CLASS_ARGUMENTS) { + /* Special case deleting the last element of a fast Array */ + if (idx == p->u.array.count - 1) { + JS_FreeValue(ctx, p->u.array.u.values[idx]); + p->u.array.count = idx; + return true; + } + if (convert_fast_array_to_array(ctx, p)) + return -1; + goto redo; + } else { + return false; + } + } + } else { + const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; + if (em && em->delete_property) { + return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom); + } + } + } + /* not found */ + return true; +} + +static int call_setter(JSContext *ctx, JSObject *setter, + JSValueConst this_obj, JSValue val, int flags) +{ + JSValue ret, func; + if (likely(setter)) { + func = JS_MKPTR(JS_TAG_OBJECT, setter); + /* Note: the field could be removed in the setter */ + func = js_dup(func); + ret = JS_CallFree(ctx, func, this_obj, 1, vc(&val)); + JS_FreeValue(ctx, val); + if (JS_IsException(ret)) + return -1; + JS_FreeValue(ctx, ret); + return true; + } else { + JS_FreeValue(ctx, val); + if ((flags & JS_PROP_THROW) || + ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { + JS_ThrowTypeError(ctx, "no setter for property"); + return -1; + } + return false; + } +} + +/* set the array length and remove the array elements if necessary. */ +static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, + int flags) +{ + uint32_t len, idx, cur_len; + int i, ret; + + /* Note: this call can reallocate the properties of 'p' */ + ret = JS_ToArrayLengthFree(ctx, &len, val, false); + if (ret) + return -1; + /* JS_ToArrayLengthFree() must be done before the read-only test */ + if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE))) + return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); + + if (likely(p->fast_array)) { + uint32_t old_len = p->u.array.count; + if (len < old_len) { + for(i = len; i < old_len; i++) { + JS_FreeValue(ctx, p->u.array.u.values[i]); + } + p->u.array.count = len; + } + p->prop[0].u.value = js_uint32(len); + } else { + /* Note: length is always a uint32 because the object is an + array */ + JS_ToUint32(ctx, &cur_len, p->prop[0].u.value); + if (len < cur_len) { + uint32_t d; + JSShape *sh; + JSShapeProperty *pr; + + d = cur_len - len; + sh = p->shape; + if (d <= sh->prop_count) { + JSAtom atom; + + /* faster to iterate */ + while (cur_len > len) { + atom = JS_NewAtomUInt32(ctx, cur_len - 1); + ret = delete_property(ctx, p, atom); + JS_FreeAtom(ctx, atom); + if (unlikely(!ret)) { + /* unlikely case: property is not + configurable */ + break; + } + cur_len--; + } + } else { + /* faster to iterate thru all the properties. Need two + passes in case one of the property is not + configurable */ + cur_len = len; + for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; + i++, pr++) { + if (pr->atom != JS_ATOM_NULL && + JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) { + if (idx >= cur_len && + !(pr->flags & JS_PROP_CONFIGURABLE)) { + cur_len = idx + 1; + } + } + } + + for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; + i++, pr++) { + if (pr->atom != JS_ATOM_NULL && + JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) { + if (idx >= cur_len) { + /* remove the property */ + delete_property(ctx, p, pr->atom); + /* WARNING: the shape may have been modified */ + sh = p->shape; + pr = get_shape_prop(sh) + i; + } + } + } + } + } else { + cur_len = len; + } + set_value(ctx, &p->prop[0].u.value, js_uint32(cur_len)); + if (unlikely(cur_len > len)) { + return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable"); + } + } + return true; +} + +/* return -1 if exception */ +static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len) +{ + uint32_t new_size; + size_t slack; + JSValue *new_array_prop; + /* XXX: potential arithmetic overflow */ + new_size = max_int(new_len, p->u.array.u1.size * 3 / 2); + new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack); + if (!new_array_prop) + return -1; + new_size += slack / sizeof(*new_array_prop); + p->u.array.u.values = new_array_prop; + p->u.array.u1.size = new_size; + return 0; +} + +/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array = + true and p->extensible = true */ +static int add_fast_array_element(JSContext *ctx, JSObject *p, + JSValue val, int flags) +{ + uint32_t new_len, array_len; + /* extend the array by one */ + /* XXX: convert to slow array if new_len > 2^31-1 elements */ + new_len = p->u.array.count + 1; + /* update the length if necessary. We assume that if the length is + not an integer, then if it >= 2^31. */ + if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) { + array_len = JS_VALUE_GET_INT(p->prop[0].u.value); + if (new_len > array_len) { + if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) { + JS_FreeValue(ctx, val); + return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); + } + p->prop[0].u.value = js_int32(new_len); + } + } + if (unlikely(new_len > p->u.array.u1.size)) { + if (expand_fast_array(ctx, p, new_len)) { + JS_FreeValue(ctx, val); + return -1; + } + } + p->u.array.u.values[new_len - 1] = val; + p->u.array.count = new_len; + return true; +} + +static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) +{ + JS_FreeValue(ctx, desc->getter); + JS_FreeValue(ctx, desc->setter); + JS_FreeValue(ctx, desc->value); +} + +/* return -1 in case of exception or true or false. Warning: 'val' is + freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD, + JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set, + the new property is not added and an error is raised. + 'obj' must be an object when obj != this_obj. + */ +static int JS_SetPropertyInternal2(JSContext *ctx, JSValueConst obj, JSAtom prop, + JSValue val, JSValueConst this_obj, int flags) +{ + JSObject *p, *p1; + JSShapeProperty *prs; + JSProperty *pr; + JSPropertyDescriptor desc; + int ret; + + switch(JS_VALUE_GET_TAG(this_obj)) { + case JS_TAG_NULL: + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); + goto fail; + case JS_TAG_UNDEFINED: + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); + goto fail; + case JS_TAG_OBJECT: + p = JS_VALUE_GET_OBJ(this_obj); + p1 = JS_VALUE_GET_OBJ(obj); + if (p == p1) + break; + goto retry2; + default: + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + obj = JS_GetPrototypePrimitive(ctx, obj); + p = NULL; + p1 = JS_VALUE_GET_OBJ(obj); + goto prototype_lookup; + } + +retry: + prs = find_own_property(&pr, p1, prop); + if (prs) { + if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE | + JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) { + /* fast case */ + set_value(ctx, &pr->u.value, val); + return true; + } else if (prs->flags & JS_PROP_LENGTH) { + assert(p->class_id == JS_CLASS_ARRAY); + assert(prop == JS_ATOM_length); + return set_array_length(ctx, p, val, flags); + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { + return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags); + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + /* JS_PROP_WRITABLE is always true for variable + references, but they are write protected in module name + spaces. */ + if (p->class_id == JS_CLASS_MODULE_NS) + goto read_only_prop; + set_value(ctx, pr->u.var_ref->pvalue, val); + return true; + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + /* Instantiate property and retry (potentially useless) */ + if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) + goto fail; + goto retry; + } else { + goto read_only_prop; + } + } + + for(;;) { + if (p1->is_exotic) { + if (p1->fast_array) { + if (__JS_AtomIsTaggedInt(prop)) { + uint32_t idx = __JS_AtomToUInt32(prop); + if (idx < p1->u.array.count) { + if (unlikely(p == p1)) + return JS_SetPropertyValue(ctx, this_obj, js_int32(idx), val, flags); + else + break; + } else if (is_typed_array(p1->class_id)) { + goto typed_array_oob; + } + } else if (is_typed_array(p1->class_id)) { + ret = JS_AtomIsNumericIndex(ctx, prop); + if (ret != 0) { + if (ret < 0) + goto fail; + typed_array_oob: + // per spec: evaluate value for side effects + if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY || + p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) { + int64_t v; + if (JS_ToBigInt64Free(ctx, &v, val)) + return -1; + } else { + val = JS_ToNumberFree(ctx, val); + JS_FreeValue(ctx, val); + if (JS_IsException(val)) + return -1; + } + return true; + } + } + } else { + const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic; + if (em) { + JSValue obj1; + if (em->set_property) { + /* set_property can free the prototype */ + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p1)); + ret = em->set_property(ctx, obj1, prop, + val, this_obj, flags); + JS_FreeValue(ctx, obj1); + JS_FreeValue(ctx, val); + return ret; + } + if (em->get_own_property) { + /* get_own_property can free the prototype */ + obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p1)); + ret = em->get_own_property(ctx, &desc, + obj1, prop); + JS_FreeValue(ctx, obj1); + if (ret < 0) + goto fail; + if (ret) { + if (desc.flags & JS_PROP_GETSET) { + JSObject *setter; + if (JS_IsUndefined(desc.setter)) + setter = NULL; + else + setter = JS_VALUE_GET_OBJ(desc.setter); + ret = call_setter(ctx, setter, this_obj, val, flags); + JS_FreeValue(ctx, desc.getter); + JS_FreeValue(ctx, desc.setter); + return ret; + } else { + JS_FreeValue(ctx, desc.value); + if (!(desc.flags & JS_PROP_WRITABLE)) + goto read_only_prop; + if (likely(p == p1)) { + ret = JS_DefineProperty(ctx, this_obj, prop, val, + JS_UNDEFINED, JS_UNDEFINED, + JS_PROP_HAS_VALUE); + JS_FreeValue(ctx, val); + return ret; + } else { + break; + } + } + } + } + } + } + } + p1 = p1->shape->proto; + prototype_lookup: + if (!p1) + break; + + retry2: + prs = find_own_property(&pr, p1, prop); + if (prs) { + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { + return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags); + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + /* Instantiate property and retry (potentially useless) */ + if (JS_AutoInitProperty(ctx, p1, prop, pr, prs)) + return -1; + goto retry2; + } else if (!(prs->flags & JS_PROP_WRITABLE)) { + goto read_only_prop; + } else { + break; + } + } + } + + if (unlikely(flags & JS_PROP_NO_ADD)) { + JS_ThrowReferenceErrorNotDefined(ctx, prop); + goto fail; + } + + if (unlikely(!p)) { + ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object"); + goto done; + } + + if (unlikely(!p->extensible)) { + ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); + goto done; + } + + if (p == JS_VALUE_GET_OBJ(obj)) { + if (p->is_exotic) { + if (p->class_id == JS_CLASS_ARRAY && p->fast_array && + __JS_AtomIsTaggedInt(prop)) { + uint32_t idx = __JS_AtomToUInt32(prop); + if (idx == p->u.array.count) { + /* fast case */ + return add_fast_array_element(ctx, p, val, flags); + } + } + goto generic_create_prop; + } else { + pr = add_property(ctx, p, prop, JS_PROP_C_W_E); + if (!pr) + goto fail; + pr->u.value = val; + return true; + } + } + + // TODO(bnoordhuis) return JSProperty slot and update in place + // when plain property (not is_exotic/setter/etc.) to avoid + // calling find_own_property() thrice? + ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); + if (ret < 0) + goto fail; + + if (ret) { + JS_FreeValue(ctx, desc.value); + if (desc.flags & JS_PROP_GETSET) { + JS_FreeValue(ctx, desc.getter); + JS_FreeValue(ctx, desc.setter); + ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); + goto done; + } else if (!(desc.flags & JS_PROP_WRITABLE) || + p->class_id == JS_CLASS_MODULE_NS) { + read_only_prop: + ret = JS_ThrowTypeErrorReadOnly(ctx, flags, prop); + goto done; + } + ret = JS_DefineProperty(ctx, this_obj, prop, val, + JS_UNDEFINED, JS_UNDEFINED, + JS_PROP_HAS_VALUE); + } else { + generic_create_prop: + ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, + flags | + JS_PROP_HAS_VALUE | + JS_PROP_HAS_ENUMERABLE | + JS_PROP_HAS_WRITABLE | + JS_PROP_HAS_CONFIGURABLE | + JS_PROP_C_W_E); + } + +done: + JS_FreeValue(ctx, val); + return ret; +fail: + JS_FreeValue(ctx, val); + return -1; +} + +static int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, + JSValue val, int flags) +{ + return JS_SetPropertyInternal2(ctx, obj, prop, val, obj, flags); +} + +int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val) +{ + return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW); +} + +/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */ +static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, + JSValue prop, JSValue val, int flags) +{ + if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && + JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { + JSObject *p; + uint32_t idx; + double d; + int32_t v; + + /* fast path for array access */ + p = JS_VALUE_GET_OBJ(this_obj); + idx = JS_VALUE_GET_INT(prop); + switch(p->class_id) { + case JS_CLASS_ARRAY: + if (unlikely(idx >= (uint32_t)p->u.array.count)) { + JSObject *p1; + JSShape *sh1; + + /* fast path to add an element to the array */ + if (idx != (uint32_t)p->u.array.count || + !p->fast_array || !p->extensible) + goto slow_path; + /* check if prototype chain has a numeric property */ + p1 = p->shape->proto; + while (p1 != NULL) { + sh1 = p1->shape; + if (p1->class_id == JS_CLASS_ARRAY) { + if (unlikely(!p1->fast_array)) + goto slow_path; + } else if (p1->class_id == JS_CLASS_OBJECT) { + if (unlikely(sh1->has_small_array_index)) + goto slow_path; + } else { + goto slow_path; + } + p1 = sh1->proto; + } + /* add element */ + return add_fast_array_element(ctx, p, val, flags); + } + set_value(ctx, &p->u.array.u.values[idx], val); + break; + case JS_CLASS_ARGUMENTS: + if (unlikely(idx >= (uint32_t)p->u.array.count)) + goto slow_path; + set_value(ctx, &p->u.array.u.values[idx], val); + break; + case JS_CLASS_UINT8C_ARRAY: + if (JS_ToUint8ClampFree(ctx, &v, val)) + goto ta_cvt_fail; + /* Note: the conversion can detach the typed array, so the + array bound check must be done after */ + if (unlikely(idx >= (uint32_t)p->u.array.count)) + goto ta_out_of_bound; + p->u.array.u.uint8_ptr[idx] = v; + break; + case JS_CLASS_INT8_ARRAY: + case JS_CLASS_UINT8_ARRAY: + if (JS_ToInt32Free(ctx, &v, val)) + goto ta_cvt_fail; + if (unlikely(idx >= (uint32_t)p->u.array.count)) + goto ta_out_of_bound; + p->u.array.u.uint8_ptr[idx] = v; + break; + case JS_CLASS_INT16_ARRAY: + case JS_CLASS_UINT16_ARRAY: + if (JS_ToInt32Free(ctx, &v, val)) + goto ta_cvt_fail; + if (unlikely(idx >= (uint32_t)p->u.array.count)) + goto ta_out_of_bound; + p->u.array.u.uint16_ptr[idx] = v; + break; + case JS_CLASS_INT32_ARRAY: + case JS_CLASS_UINT32_ARRAY: + if (JS_ToInt32Free(ctx, &v, val)) + goto ta_cvt_fail; + if (unlikely(idx >= (uint32_t)p->u.array.count)) + goto ta_out_of_bound; + p->u.array.u.uint32_ptr[idx] = v; + break; + case JS_CLASS_BIG_INT64_ARRAY: + case JS_CLASS_BIG_UINT64_ARRAY: + /* XXX: need specific conversion function */ + { + int64_t v; + if (JS_ToBigInt64Free(ctx, &v, val)) + goto ta_cvt_fail; + if (unlikely(idx >= (uint32_t)p->u.array.count)) + goto ta_out_of_bound; + p->u.array.u.uint64_ptr[idx] = v; + } + break; + case JS_CLASS_FLOAT16_ARRAY: + if (JS_ToFloat64Free(ctx, &d, val)) + goto ta_cvt_fail; + if (unlikely(idx >= (uint32_t)p->u.array.count)) + goto ta_out_of_bound; + p->u.array.u.fp16_ptr[idx] = tofp16(d); + break; + case JS_CLASS_FLOAT32_ARRAY: + if (JS_ToFloat64Free(ctx, &d, val)) + goto ta_cvt_fail; + if (unlikely(idx >= (uint32_t)p->u.array.count)) + goto ta_out_of_bound; + p->u.array.u.float_ptr[idx] = d; + break; + case JS_CLASS_FLOAT64_ARRAY: + if (JS_ToFloat64Free(ctx, &d, val)) { + ta_cvt_fail: + if (flags & JS_PROP_REFLECT_DEFINE_PROPERTY) { + JS_FreeValue(ctx, JS_GetException(ctx)); + return false; + } + return -1; + } + if (unlikely(idx >= (uint32_t)p->u.array.count)) { + ta_out_of_bound: + if (typed_array_is_oob(p)) + if (flags & JS_PROP_DEFINE_PROPERTY) + return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); + return true; // per spec: no OOB exception + } + p->u.array.u.double_ptr[idx] = d; + break; + default: + goto slow_path; + } + return true; + } else { + JSAtom atom; + int ret; + slow_path: + atom = JS_ValueToAtom(ctx, prop); + JS_FreeValue(ctx, prop); + if (unlikely(atom == JS_ATOM_NULL)) { + JS_FreeValue(ctx, val); + return -1; + } + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags); + JS_FreeAtom(ctx, atom); + return ret; + } +} + +int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, + uint32_t idx, JSValue val) +{ + return JS_SetPropertyValue(ctx, this_obj, js_uint32(idx), val, + JS_PROP_THROW); +} + +int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, + int64_t idx, JSValue val) +{ + JSAtom prop; + int res; + + if ((uint64_t)idx <= INT32_MAX) { + /* fast path for fast arrays */ + return JS_SetPropertyValue(ctx, this_obj, js_int32(idx), val, + JS_PROP_THROW); + } + prop = JS_NewAtomInt64(ctx, idx); + if (prop == JS_ATOM_NULL) { + JS_FreeValue(ctx, val); + return -1; + } + res = JS_SetProperty(ctx, this_obj, prop, val); + JS_FreeAtom(ctx, prop); + return res; +} + +/* `prop` may be pure ASCII or UTF-8 encoded */ +int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, + const char *prop, JSValue val) +{ + JSAtom atom; + int ret; + atom = JS_NewAtom(ctx, prop); + if (atom == JS_ATOM_NULL) { + JS_FreeValue(ctx, val); + return -1; + } + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW); + JS_FreeAtom(ctx, atom); + return ret; +} + +/* compute the property flags. For each flag: (JS_PROP_HAS_x forces + it, otherwise def_flags is used) + Note: makes assumption about the bit pattern of the flags +*/ +static int get_prop_flags(int flags, int def_flags) +{ + int mask; + mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E; + return (flags & mask) | (def_flags & ~mask); +} + +static int JS_CreateProperty(JSContext *ctx, JSObject *p, + JSAtom prop, JSValueConst val, + JSValueConst getter, JSValueConst setter, + int flags) +{ + JSProperty *pr; + int ret, prop_flags; + + /* add a new property or modify an existing exotic one */ + if (p->is_exotic) { + if (p->class_id == JS_CLASS_ARRAY) { + uint32_t idx, len; + + if (p->fast_array) { + if (__JS_AtomIsTaggedInt(prop)) { + idx = __JS_AtomToUInt32(prop); + if (idx == p->u.array.count) { + if (!p->extensible) + goto not_extensible; + if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) + goto convert_to_array; + prop_flags = get_prop_flags(flags, 0); + if (prop_flags != JS_PROP_C_W_E) + goto convert_to_array; + return add_fast_array_element(ctx, p, + js_dup(val), flags); + } else { + goto convert_to_array; + } + } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) { + /* convert the fast array to normal array */ + convert_to_array: + if (convert_fast_array_to_array(ctx, p)) + return -1; + goto generic_array; + } + } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) { + JSProperty *plen; + JSShapeProperty *pslen; + generic_array: + /* update the length field */ + plen = &p->prop[0]; + JS_ToUint32(ctx, &len, plen->u.value); + if ((idx + 1) > len) { + pslen = get_shape_prop(p->shape); + if (unlikely(!(pslen->flags & JS_PROP_WRITABLE))) + return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); + /* XXX: should update the length after defining + the property */ + len = idx + 1; + set_value(ctx, &plen->u.value, js_uint32(len)); + } + } + } else if (is_typed_array(p->class_id)) { + ret = JS_AtomIsNumericIndex(ctx, prop); + if (ret != 0) { + if (ret < 0) + return -1; + return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array"); + } + } else if (!(flags & JS_PROP_NO_EXOTIC)) { + const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; + if (em) { + if (em->define_own_property) { + return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), + prop, val, getter, setter, flags); + } + ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + if (ret < 0) + return -1; + if (!ret) + goto not_extensible; + } + } + } + + if (!p->extensible) { + not_extensible: + return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); + } + + if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { + prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | + JS_PROP_GETSET; + } else { + prop_flags = flags & JS_PROP_C_W_E; + } + pr = add_property(ctx, p, prop, prop_flags); + if (unlikely(!pr)) + return -1; + if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { + pr->u.getset.getter = NULL; + if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) { + pr->u.getset.getter = + JS_VALUE_GET_OBJ(js_dup(getter)); + } + pr->u.getset.setter = NULL; + if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) { + pr->u.getset.setter = + JS_VALUE_GET_OBJ(js_dup(setter)); + } + } else { + if (flags & JS_PROP_HAS_VALUE) { + pr->u.value = js_dup(val); + } else { + pr->u.value = JS_UNDEFINED; + } + } + return true; +} + +/* return false if not OK */ +static bool check_define_prop_flags(int prop_flags, int flags) +{ + bool has_accessor, is_getset; + + if (!(prop_flags & JS_PROP_CONFIGURABLE)) { + if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) == + (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) { + return false; + } + if ((flags & JS_PROP_HAS_ENUMERABLE) && + (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE)) + return false; + } + if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | + JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { + if (!(prop_flags & JS_PROP_CONFIGURABLE)) { + has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0); + is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET); + if (has_accessor != is_getset) + return false; + if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) { + /* not writable: cannot set the writable bit */ + if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == + (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) + return false; + } + } + } + return true; +} + +/* ensure that the shape can be safely modified */ +static int js_shape_prepare_update(JSContext *ctx, JSObject *p, + JSShapeProperty **pprs) +{ + JSShape *sh; + uint32_t idx = 0; /* prevent warning */ + + sh = p->shape; + if (sh->is_hashed) { + if (sh->header.ref_count != 1) { + if (pprs) + idx = *pprs - get_shape_prop(sh); + /* clone the shape (the resulting one is no longer hashed) */ + sh = js_clone_shape(ctx, sh); + if (!sh) + return -1; + js_free_shape(ctx->rt, p->shape); + p->shape = sh; + if (pprs) + *pprs = get_shape_prop(sh) + idx; + } else { + js_shape_hash_unlink(ctx->rt, sh); + sh->is_hashed = false; + } + } + return 0; +} + +static int js_update_property_flags(JSContext *ctx, JSObject *p, + JSShapeProperty **pprs, int flags) +{ + if (flags != (*pprs)->flags) { + if (js_shape_prepare_update(ctx, p, pprs)) + return -1; + (*pprs)->flags = flags; + } + return 0; +} + +/* allowed flags: + JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE + JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE, + JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE, + JS_PROP_THROW, JS_PROP_NO_EXOTIC. + If JS_PROP_THROW is set, return an exception instead of false. + if JS_PROP_NO_EXOTIC is set, do not call the exotic + define_own_property callback. + return -1 (exception), false or true. +*/ +int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, + JSAtom prop, JSValueConst val, + JSValueConst getter, JSValueConst setter, int flags) +{ + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + int mask, res; + + if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) { + JS_ThrowTypeErrorNotAnObject(ctx); + return -1; + } + p = JS_VALUE_GET_OBJ(this_obj); + + redo_prop_update: + prs = find_own_property(&pr, p, prop); + if (prs) { + /* the range of the Array length property is always tested before */ + if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) { + uint32_t array_length; + if (JS_ToArrayLengthFree(ctx, &array_length, + js_dup(val), false)) { + return -1; + } + /* this code relies on the fact that Uint32 are never allocated */ + val = js_uint32(array_length); + /* prs may have been modified */ + prs = find_own_property(&pr, p, prop); + assert(prs != NULL); + } + /* property already exists */ + if (!check_define_prop_flags(prs->flags, flags)) { + not_configurable: + return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable"); + } + + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + /* Instantiate property and retry */ + if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) + return -1; + goto redo_prop_update; + } + + if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | + JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { + if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { + JSObject *new_getter, *new_setter; + + if (JS_IsFunction(ctx, getter)) { + new_getter = JS_VALUE_GET_OBJ(getter); + } else { + new_getter = NULL; + } + if (JS_IsFunction(ctx, setter)) { + new_setter = JS_VALUE_GET_OBJ(setter); + } else { + new_setter = NULL; + } + + if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) { + if (js_shape_prepare_update(ctx, p, &prs)) + return -1; + /* convert to getset */ + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + free_var_ref(ctx->rt, pr->u.var_ref); + } else { + JS_FreeValue(ctx, pr->u.value); + } + prs->flags = (prs->flags & + (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | + JS_PROP_GETSET; + pr->u.getset.getter = NULL; + pr->u.getset.setter = NULL; + } else { + if (!(prs->flags & JS_PROP_CONFIGURABLE)) { + if ((flags & JS_PROP_HAS_GET) && + new_getter != pr->u.getset.getter) { + goto not_configurable; + } + if ((flags & JS_PROP_HAS_SET) && + new_setter != pr->u.getset.setter) { + goto not_configurable; + } + } + } + if (flags & JS_PROP_HAS_GET) { + if (pr->u.getset.getter) + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); + if (new_getter) + js_dup(getter); + pr->u.getset.getter = new_getter; + } + if (flags & JS_PROP_HAS_SET) { + if (pr->u.getset.setter) + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); + if (new_setter) + js_dup(setter); + pr->u.getset.setter = new_setter; + } + } else { + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { + /* convert to data descriptor */ + if (js_shape_prepare_update(ctx, p, &prs)) + return -1; + if (pr->u.getset.getter) + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); + if (pr->u.getset.setter) + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); + prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE); + pr->u.value = JS_UNDEFINED; + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + /* Note: JS_PROP_VARREF is always writable */ + } else { + if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 && + (flags & JS_PROP_HAS_VALUE)) { + if (!js_same_value(ctx, val, pr->u.value)) { + goto not_configurable; + } else { + return true; + } + } + } + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + if (flags & JS_PROP_HAS_VALUE) { + if (p->class_id == JS_CLASS_MODULE_NS) { + /* JS_PROP_WRITABLE is always true for variable + references, but they are write protected in module name + spaces. */ + if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue)) + goto not_configurable; + } + /* update the reference */ + set_value(ctx, pr->u.var_ref->pvalue, js_dup(val)); + } + /* if writable is set to false, no longer a + reference (for mapped arguments) */ + if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) { + JSValue val1; + if (js_shape_prepare_update(ctx, p, &prs)) + return -1; + val1 = js_dup(*pr->u.var_ref->pvalue); + free_var_ref(ctx->rt, pr->u.var_ref); + pr->u.value = val1; + prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE); + } + } else if (prs->flags & JS_PROP_LENGTH) { + if (flags & JS_PROP_HAS_VALUE) { + /* Note: no JS code is executable because + 'val' is guaranted to be a Uint32 */ + res = set_array_length(ctx, p, js_dup(val), flags); + } else { + res = true; + } + /* still need to reset the writable flag if + needed. The JS_PROP_LENGTH is kept because the + Uint32 test is still done if the length + property is read-only. */ + if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == + JS_PROP_HAS_WRITABLE) { + prs = get_shape_prop(p->shape); + if (js_update_property_flags(ctx, p, &prs, + prs->flags & ~JS_PROP_WRITABLE)) + return -1; + } + return res; + } else { + if (flags & JS_PROP_HAS_VALUE) { + JS_FreeValue(ctx, pr->u.value); + pr->u.value = js_dup(val); + } + if (flags & JS_PROP_HAS_WRITABLE) { + if (js_update_property_flags(ctx, p, &prs, + (prs->flags & ~JS_PROP_WRITABLE) | + (flags & JS_PROP_WRITABLE))) + return -1; + } + } + } + } + mask = 0; + if (flags & JS_PROP_HAS_CONFIGURABLE) + mask |= JS_PROP_CONFIGURABLE; + if (flags & JS_PROP_HAS_ENUMERABLE) + mask |= JS_PROP_ENUMERABLE; + if (js_update_property_flags(ctx, p, &prs, + (prs->flags & ~mask) | (flags & mask))) + return -1; + return true; + } + + /* handle modification of fast array elements */ + if (p->fast_array) { + uint32_t idx; + uint32_t prop_flags; + if (p->class_id == JS_CLASS_ARRAY) { + if (__JS_AtomIsTaggedInt(prop)) { + idx = __JS_AtomToUInt32(prop); + if (idx < p->u.array.count) { + prop_flags = get_prop_flags(flags, JS_PROP_C_W_E); + if (prop_flags != JS_PROP_C_W_E) + goto convert_to_slow_array; + if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { + convert_to_slow_array: + if (convert_fast_array_to_array(ctx, p)) + return -1; + else + goto redo_prop_update; + } + if (flags & JS_PROP_HAS_VALUE) { + set_value(ctx, &p->u.array.u.values[idx], js_dup(val)); + } + return true; + } + } + } else if (is_typed_array(p->class_id)) { + JSValue num; + int ret; + + if (!__JS_AtomIsTaggedInt(prop)) { + /* slow path with to handle all numeric indexes */ + num = JS_AtomIsNumericIndex1(ctx, prop); + if (JS_IsUndefined(num)) + goto typed_array_done; + if (JS_IsException(num)) + return -1; + ret = JS_NumberIsInteger(ctx, num); + if (ret < 0) { + JS_FreeValue(ctx, num); + return -1; + } + if (!ret) { + JS_FreeValue(ctx, num); + return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array"); + } + ret = JS_NumberIsNegativeOrMinusZero(ctx, num); + JS_FreeValue(ctx, num); + if (ret) { + return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array"); + } + if (!__JS_AtomIsTaggedInt(prop)) + goto typed_array_oob; + } + idx = __JS_AtomToUInt32(prop); + /* if the typed array is detached, p->u.array.count = 0 */ + if (idx >= p->u.array.count) { + typed_array_oob: + return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array"); + } + prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) || + prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) { + return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags"); + } + if (flags & JS_PROP_HAS_VALUE) { + return JS_SetPropertyValue(ctx, this_obj, js_int32(idx), js_dup(val), flags); + } + return true; + typed_array_done: ; + } + } + + return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags); +} + +static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj, + JSAtom prop, JSAutoInitIDEnum id, + void *opaque, int flags) +{ + JSObject *p; + JSProperty *pr; + + if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) + return false; + + p = JS_VALUE_GET_OBJ(this_obj); + + if (find_own_property(&pr, p, prop)) { + /* property already exists */ + abort(); + return false; + } + + /* Specialized CreateProperty */ + pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT); + if (unlikely(!pr)) + return -1; + pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx); + assert((pr->u.init.realm_and_id & 3) == 0); + assert(id <= 3); + pr->u.init.realm_and_id |= id; + pr->u.init.opaque = opaque; + return true; +} + +/* shortcut to add or redefine a new property value */ +int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, + JSAtom prop, JSValue val, int flags) +{ + int ret; + ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED, + flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); + JS_FreeValue(ctx, val); + return ret; +} + +int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj, + JSValue prop, JSValue val, int flags) +{ + JSAtom atom; + int ret; + atom = JS_ValueToAtom(ctx, prop); + JS_FreeValue(ctx, prop); + if (unlikely(atom == JS_ATOM_NULL)) { + JS_FreeValue(ctx, val); + return -1; + } + ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags); + JS_FreeAtom(ctx, atom); + return ret; +} + +int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, + uint32_t idx, JSValue val, int flags) +{ + return JS_DefinePropertyValueValue(ctx, this_obj, js_uint32(idx), + val, flags); +} + +int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj, + int64_t idx, JSValue val, int flags) +{ + return JS_DefinePropertyValueValue(ctx, this_obj, js_int64(idx), + val, flags); +} + +/* `prop` may be pure ASCII or UTF-8 encoded */ +int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, + const char *prop, JSValue val, int flags) +{ + JSAtom atom; + int ret; + atom = JS_NewAtom(ctx, prop); + if (atom == JS_ATOM_NULL) { + JS_FreeValue(ctx, val); + return -1; + } + ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags); + JS_FreeAtom(ctx, atom); + return ret; +} + +/* shortcut to add getter & setter */ +int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, + JSAtom prop, JSValue getter, JSValue setter, + int flags) +{ + int ret; + ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter, + flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET | + JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE); + JS_FreeValue(ctx, getter); + JS_FreeValue(ctx, setter); + return ret; +} + +static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj, + int64_t idx, JSValue val, int flags) +{ + return JS_DefinePropertyValueValue(ctx, this_obj, js_int64(idx), + val, flags | JS_PROP_CONFIGURABLE | + JS_PROP_ENUMERABLE | JS_PROP_WRITABLE); +} + + +/* return true if 'obj' has a non empty 'name' string */ +static bool js_object_has_name(JSContext *ctx, JSValue obj) +{ + JSProperty *pr; + JSShapeProperty *prs; + JSValue val; + JSString *p; + + prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name); + if (!prs) + return false; + if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL) + return true; + val = pr->u.value; + if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) + return true; + p = JS_VALUE_GET_STRING(val); + return (p->len != 0); +} + +static int JS_DefineObjectName(JSContext *ctx, JSValue obj, + JSAtom name, int flags) +{ + if (name != JS_ATOM_NULL + && JS_IsObject(obj) + && !js_object_has_name(ctx, obj) + && JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) { + return -1; + } + return 0; +} + +static int JS_DefineObjectNameComputed(JSContext *ctx, JSValue obj, + JSValue str, int flags) +{ + if (JS_IsObject(obj) && + !js_object_has_name(ctx, obj)) { + JSAtom prop; + JSValue name_str; + prop = JS_ValueToAtom(ctx, str); + if (prop == JS_ATOM_NULL) + return -1; + name_str = js_get_function_name(ctx, prop); + JS_FreeAtom(ctx, prop); + if (JS_IsException(name_str)) + return -1; + if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0) + return -1; + } + return 0; +} + +#define DEFINE_GLOBAL_LEX_VAR (1 << 7) +#define DEFINE_GLOBAL_FUNC_VAR (1 << 6) + +static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop) +{ + return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop); +} + +/* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */ +/* XXX: could support exotic global object. */ +static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags) +{ + JSObject *p; + JSShapeProperty *prs; + + p = JS_VALUE_GET_OBJ(ctx->global_obj); + prs = find_own_property1(p, prop); + /* XXX: should handle JS_PROP_AUTOINIT */ + if (flags & DEFINE_GLOBAL_LEX_VAR) { + if (prs && !(prs->flags & JS_PROP_CONFIGURABLE)) + goto fail_redeclaration; + } else { + if (!prs && !p->extensible) + goto define_error; + if (flags & DEFINE_GLOBAL_FUNC_VAR) { + if (prs) { + if (!(prs->flags & JS_PROP_CONFIGURABLE) && + ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET || + ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) != + (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) { + define_error: + JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'", + prop); + return -1; + } + } + } + } + /* check if there already is a lexical declaration */ + p = JS_VALUE_GET_OBJ(ctx->global_var_obj); + prs = find_own_property1(p, prop); + if (prs) { + fail_redeclaration: + JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop); + return -1; + } + return 0; +} + +/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) | + JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */ +/* XXX: could support exotic global object. */ +static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags) +{ + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + JSValue val; + int flags; + + if (def_flags & DEFINE_GLOBAL_LEX_VAR) { + p = JS_VALUE_GET_OBJ(ctx->global_var_obj); + flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) | + JS_PROP_CONFIGURABLE; + val = JS_UNINITIALIZED; + } else { + p = JS_VALUE_GET_OBJ(ctx->global_obj); + flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | + (def_flags & JS_PROP_CONFIGURABLE); + val = JS_UNDEFINED; + } + prs = find_own_property1(p, prop); + if (prs) + return 0; + if (!p->extensible) + return 0; + pr = add_property(ctx, p, prop, flags); + if (unlikely(!pr)) + return -1; + pr->u.value = val; + return 0; +} + +/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */ +/* XXX: could support exotic global object. */ +static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop, + JSValue func, int def_flags) +{ + + JSObject *p; + JSShapeProperty *prs; + int flags; + + p = JS_VALUE_GET_OBJ(ctx->global_obj); + prs = find_own_property1(p, prop); + flags = JS_PROP_HAS_VALUE | JS_PROP_THROW; + if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) { + flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags | + JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE; + } + if (JS_DefineProperty(ctx, ctx->global_obj, prop, func, + JS_UNDEFINED, JS_UNDEFINED, flags) < 0) + return -1; + return 0; +} + +static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop, + bool throw_ref_error) +{ + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + + /* no exotic behavior is possible in global_var_obj */ + p = JS_VALUE_GET_OBJ(ctx->global_var_obj); + prs = find_own_property(&pr, p, prop); + if (prs) { + /* XXX: should handle JS_PROP_TMASK properties */ + if (unlikely(JS_IsUninitialized(pr->u.value))) + return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); + return js_dup(pr->u.value); + } + return JS_GetPropertyInternal(ctx, ctx->global_obj, prop, + ctx->global_obj, throw_ref_error); +} + +/* construct a reference to a global variable */ +static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp) +{ + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + + /* no exotic behavior is possible in global_var_obj */ + p = JS_VALUE_GET_OBJ(ctx->global_var_obj); + prs = find_own_property(&pr, p, prop); + if (prs) { + /* XXX: should handle JS_PROP_AUTOINIT properties? */ + /* XXX: conformance: do these tests in + OP_put_var_ref/OP_get_var_ref ? */ + if (unlikely(JS_IsUninitialized(pr->u.value))) { + JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); + return -1; + } + if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) { + return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop); + } + sp[0] = js_dup(ctx->global_var_obj); + } else { + int ret; + ret = JS_HasProperty(ctx, ctx->global_obj, prop); + if (ret < 0) + return -1; + if (ret) { + sp[0] = js_dup(ctx->global_obj); + } else { + sp[0] = JS_UNDEFINED; + } + } + sp[1] = JS_AtomToValue(ctx, prop); + return 0; +} + +/* use for strict variable access: test if the variable exists */ +static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop) +{ + JSObject *p; + JSShapeProperty *prs; + int ret; + + /* no exotic behavior is possible in global_var_obj */ + p = JS_VALUE_GET_OBJ(ctx->global_var_obj); + prs = find_own_property1(p, prop); + if (prs) { + ret = true; + } else { + ret = JS_HasProperty(ctx, ctx->global_obj, prop); + if (ret < 0) + return -1; + } + return ret; +} + +/* flag = 0: normal variable write + flag = 1: initialize lexical variable + flag = 2: normal variable write, strict check was done before +*/ +static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val, + int flag) +{ + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + int flags; + + /* no exotic behavior is possible in global_var_obj */ + p = JS_VALUE_GET_OBJ(ctx->global_var_obj); + prs = find_own_property(&pr, p, prop); + if (prs) { + /* XXX: should handle JS_PROP_AUTOINIT properties? */ + if (flag != 1) { + if (unlikely(JS_IsUninitialized(pr->u.value))) { + JS_FreeValue(ctx, val); + JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); + return -1; + } + if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) { + JS_FreeValue(ctx, val); + return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop); + } + } + set_value(ctx, &pr->u.value, val); + return 0; + } + flags = JS_PROP_THROW_STRICT; + if (is_strict_mode(ctx)) + flags |= JS_PROP_NO_ADD; + return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags); +} + +/* return -1, false or true */ +static int JS_DeleteGlobalVar(JSContext *ctx, JSAtom prop) +{ + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + int ret; + + /* 9.1.1.4.7 DeleteBinding ( N ) */ + p = JS_VALUE_GET_OBJ(ctx->global_var_obj); + prs = find_own_property(&pr, p, prop); + if (prs) + return false; /* lexical variables cannot be deleted */ + ret = JS_HasProperty(ctx, ctx->global_obj, prop); + if (ret < 0) + return -1; + if (ret) { + return JS_DeleteProperty(ctx, ctx->global_obj, prop, 0); + } else { + return true; + } +} + +/* return -1, false or true. return false if not configurable or + invalid object. return -1 in case of exception. + flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */ +int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags) +{ + JSValue obj1; + JSObject *p; + int res; + + obj1 = JS_ToObject(ctx, obj); + if (JS_IsException(obj1)) + return -1; + p = JS_VALUE_GET_OBJ(obj1); + res = delete_property(ctx, p, prop); + JS_FreeValue(ctx, obj1); + if (res != false) + return res; + if ((flags & JS_PROP_THROW) || + ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { + JS_ThrowTypeError(ctx, "could not delete property"); + return -1; + } + return false; +} + +int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags) +{ + JSAtom prop; + int res; + + if ((uint64_t)idx <= JS_ATOM_MAX_INT) { + /* fast path for fast arrays */ + return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags); + } + prop = JS_NewAtomInt64(ctx, idx); + if (prop == JS_ATOM_NULL) + return -1; + res = JS_DeleteProperty(ctx, obj, prop, flags); + JS_FreeAtom(ctx, prop); + return res; +} + +bool JS_IsFunction(JSContext *ctx, JSValueConst val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return false; + p = JS_VALUE_GET_OBJ(val); + switch(p->class_id) { + case JS_CLASS_BYTECODE_FUNCTION: + return true; + case JS_CLASS_PROXY: + return p->u.proxy_data->is_func; + default: + return (ctx->rt->class_array[p->class_id].call != NULL); + } +} + +static bool JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, + int magic) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return false; + p = JS_VALUE_GET_OBJ(val); + if (p->class_id == JS_CLASS_C_FUNCTION) + return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic); + else + return false; +} + +bool JS_IsConstructor(JSContext *ctx, JSValueConst val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return false; + p = JS_VALUE_GET_OBJ(val); + return p->is_constructor; +} + +bool JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, bool val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) + return false; + p = JS_VALUE_GET_OBJ(func_obj); + p->is_constructor = val; + return true; +} + +bool JS_IsRegExp(JSValueConst val) +{ + return JS_CLASS_REGEXP == JS_GetClassID(val); +} + +bool JS_IsMap(JSValueConst val) +{ + return JS_CLASS_MAP == JS_GetClassID(val); +} + +bool JS_IsSet(JSValueConst val) +{ + return JS_CLASS_SET == JS_GetClassID(val); +} + +bool JS_IsWeakRef(JSValueConst val) +{ + return JS_CLASS_WEAK_REF == JS_GetClassID(val); +} + +bool JS_IsWeakSet(JSValueConst val) +{ + return JS_CLASS_WEAKSET == JS_GetClassID(val); +} + +bool JS_IsWeakMap(JSValueConst val) +{ + return JS_CLASS_WEAKMAP == JS_GetClassID(val); +} + +bool JS_IsDataView(JSValueConst val) +{ + return JS_CLASS_DATAVIEW == JS_GetClassID(val); +} + +bool JS_IsError(JSValueConst val) +{ + return JS_CLASS_ERROR == JS_GetClassID(val); +} + +/* used to avoid catching interrupt exceptions */ +bool JS_IsUncatchableError(JSValueConst val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return false; + p = JS_VALUE_GET_OBJ(val); + return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error; +} + +static void js_set_uncatchable_error(JSContext *ctx, JSValueConst val, bool flag) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return; + p = JS_VALUE_GET_OBJ(val); + if (p->class_id == JS_CLASS_ERROR) + p->is_uncatchable_error = flag; +} + +void JS_SetUncatchableError(JSContext *ctx, JSValueConst val) +{ + js_set_uncatchable_error(ctx, val, true); +} + +void JS_ClearUncatchableError(JSContext *ctx, JSValueConst val) +{ + js_set_uncatchable_error(ctx, val, false); +} + +void JS_ResetUncatchableError(JSContext *ctx) +{ + js_set_uncatchable_error(ctx, ctx->rt->current_exception, false); +} + +int JS_SetOpaque(JSValueConst obj, void *opaque) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { + p = JS_VALUE_GET_OBJ(obj); + // User code can't set the opaque of internal objects. + if (p->class_id >= JS_CLASS_INIT_COUNT) { + p->u.opaque = opaque; + return 0; + } + } + + return -1; +} + +/* |obj| must be a JSObject of an internal class. */ +static void JS_SetOpaqueInternal(JSValueConst obj, void *opaque) +{ + JSObject *p; + assert(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT); + p = JS_VALUE_GET_OBJ(obj); + assert(p->class_id < JS_CLASS_INIT_COUNT); + p->u.opaque = opaque; +} + +/* return NULL if not an object of class class_id */ +void *JS_GetOpaque(JSValueConst obj, JSClassID class_id) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + return NULL; + p = JS_VALUE_GET_OBJ(obj); + if (p->class_id != class_id) + return NULL; + return p->u.opaque; +} + +void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id) +{ + void *p = JS_GetOpaque(obj, class_id); + if (unlikely(!p)) { + JS_ThrowTypeErrorInvalidClass(ctx, class_id); + } + return p; +} + +void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { + *class_id = 0; + return NULL; + } + p = JS_VALUE_GET_OBJ(obj); + *class_id = p->class_id; + return p->u.opaque; +} + +static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint) +{ + int i; + bool force_ordinary; + + JSAtom method_name; + JSValue method, ret; + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return val; + force_ordinary = hint & HINT_FORCE_ORDINARY; + hint &= ~HINT_FORCE_ORDINARY; + if (!force_ordinary) { + method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive); + if (JS_IsException(method)) + goto exception; + /* ECMA says *If exoticToPrim is not undefined* but tests in + test262 use null as a non callable converter */ + if (!JS_IsUndefined(method) && !JS_IsNull(method)) { + JSAtom atom; + JSValue arg; + switch(hint) { + case HINT_STRING: + atom = JS_ATOM_string; + break; + case HINT_NUMBER: + atom = JS_ATOM_number; + break; + default: + case HINT_NONE: + atom = JS_ATOM_default; + break; + } + arg = JS_AtomToString(ctx, atom); + ret = JS_CallFree(ctx, method, val, 1, vc(&arg)); + JS_FreeValue(ctx, arg); + if (JS_IsException(ret)) + goto exception; + JS_FreeValue(ctx, val); + if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) + return ret; + JS_FreeValue(ctx, ret); + return JS_ThrowTypeError(ctx, "toPrimitive"); + } + } + if (hint != HINT_STRING) + hint = HINT_NUMBER; + for(i = 0; i < 2; i++) { + if ((i ^ hint) == 0) { + method_name = JS_ATOM_toString; + } else { + method_name = JS_ATOM_valueOf; + } + method = JS_GetProperty(ctx, val, method_name); + if (JS_IsException(method)) + goto exception; + if (JS_IsFunction(ctx, method)) { + ret = JS_CallFree(ctx, method, val, 0, NULL); + if (JS_IsException(ret)) + goto exception; + if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) { + JS_FreeValue(ctx, val); + return ret; + } + JS_FreeValue(ctx, ret); + } else { + JS_FreeValue(ctx, method); + } + } + JS_ThrowTypeError(ctx, "toPrimitive"); +exception: + JS_FreeValue(ctx, val); + return JS_EXCEPTION; +} + +static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint) +{ + return JS_ToPrimitiveFree(ctx, js_dup(val), hint); +} + +void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + return; + p = JS_VALUE_GET_OBJ(obj); + p->is_HTMLDDA = true; +} + +static inline bool JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + return false; + p = JS_VALUE_GET_OBJ(obj); + return p->is_HTMLDDA; +} + +static int JS_ToBoolFree(JSContext *ctx, JSValue val) +{ + uint32_t tag = JS_VALUE_GET_TAG(val); + switch(tag) { + case JS_TAG_INT: + return JS_VALUE_GET_INT(val) != 0; + case JS_TAG_BOOL: + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + return JS_VALUE_GET_INT(val); + case JS_TAG_EXCEPTION: + return -1; + case JS_TAG_STRING: + { + bool ret = JS_VALUE_GET_STRING(val)->len != 0; + JS_FreeValue(ctx, val); + return ret; + } + case JS_TAG_SHORT_BIG_INT: + return JS_VALUE_GET_SHORT_BIG_INT(val) != 0; + case JS_TAG_BIG_INT: + { + JSBigInt *p = JS_VALUE_GET_PTR(val); + bool ret; + int i; + + /* fail safe: we assume it is not necessarily + normalized. Beginning from the MSB ensures that the + test is fast. */ + ret = false; + for(i = p->len - 1; i >= 0; i--) { + if (p->tab[i] != 0) { + ret = true; + break; + } + } + JS_FreeValue(ctx, val); + return ret; + } + case JS_TAG_OBJECT: + { + JSObject *p = JS_VALUE_GET_OBJ(val); + bool ret = !p->is_HTMLDDA; + JS_FreeValue(ctx, val); + return ret; + } + break; + default: + if (JS_TAG_IS_FLOAT64(tag)) { + double d = JS_VALUE_GET_FLOAT64(val); + return !isnan(d) && d != 0; + } else { + JS_FreeValue(ctx, val); + return true; + } + } +} + +int JS_ToBool(JSContext *ctx, JSValueConst val) +{ + return JS_ToBoolFree(ctx, js_dup(val)); +} + +/* pc points to pure ASCII or UTF-8, null terminated contents */ +static int skip_spaces(const char *pc) +{ + const uint8_t *p, *p_next, *p_start; + uint32_t c; + + p = p_start = (const uint8_t *)pc; + for (;;) { + c = *p++; + if (c < 0x80) { + if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20))) + break; + } else { + c = utf8_decode(p - 1, &p_next); + /* no need to test for invalid UTF-8, 0xFFFD is not a space */ + if (!lre_is_space(c)) + break; + p = p_next; + } + } + return p - 1 - p_start; +} + +static inline int js_to_digit(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'z') + return c - 'a' + 10; + else + return 36; +} + +/* bigint support */ + +#define ADDC(res, carry_out, op1, op2, carry_in) \ +do { \ + js_limb_t __v, __a, __k, __k1; \ + __v = (op1); \ + __a = __v + (op2); \ + __k1 = __a < __v; \ + __k = (carry_in); \ + __a = __a + __k; \ + carry_out = (__a < __k) | __k1; \ + res = __a; \ +} while (0) + +/* a != 0 */ +static inline js_limb_t js_limb_clz(js_limb_t a) +{ + if (!a) + return JS_LIMB_BITS; + return clz32(a); +} + +static js_limb_t js_mp_add(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2, + js_limb_t n, js_limb_t carry) +{ + int i; + for(i = 0;i < n; i++) { + ADDC(res[i], carry, op1[i], op2[i], carry); + } + return carry; +} + +static js_limb_t js_mp_sub(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2, + int n, js_limb_t carry) +{ + int i; + js_limb_t k, a, v, k1; + + k = carry; + for(i=0;i v; + v = a - k; + k = (v > a) | k1; + res[i] = v; + } + return k; +} + +/* compute 0 - op2. carry = 0 or 1. */ +static js_limb_t js_mp_neg(js_limb_t *res, const js_limb_t *op2, int n) +{ + int i; + js_limb_t v, carry; + + carry = 1; + for(i=0;i> JS_LIMB_BITS; + } + return l; +} + +static js_limb_t js_mp_div1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n, + js_limb_t b, js_limb_t r) +{ + js_slimb_t i; + js_dlimb_t a1; + for(i = n - 1; i >= 0; i--) { + a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i]; + tabr[i] = a1 / b; + r = a1 % b; + } + return r; +} + +/* tabr[] += taba[] * b, return the high word. */ +static js_limb_t js_mp_add_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n, + js_limb_t b) +{ + js_limb_t i, l; + js_dlimb_t t; + + l = 0; + for(i = 0; i < n; i++) { + t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l + tabr[i]; + tabr[i] = t; + l = t >> JS_LIMB_BITS; + } + return l; +} + +/* size of the result : op1_size + op2_size. */ +static void js_mp_mul_basecase(js_limb_t *result, + const js_limb_t *op1, js_limb_t op1_size, + const js_limb_t *op2, js_limb_t op2_size) +{ + int i; + js_limb_t r; + + result[op1_size] = js_mp_mul1(result, op1, op1_size, op2[0], 0); + for(i=1;i> JS_LIMB_BITS); + } + return l; +} + +/* WARNING: d must be >= 2^(JS_LIMB_BITS-1) */ +static inline js_limb_t js_udiv1norm_init(js_limb_t d) +{ + js_limb_t a0, a1; + a1 = -d - 1; + a0 = -1; + return (((js_dlimb_t)a1 << JS_LIMB_BITS) | a0) / d; +} + +/* return the quotient and the remainder in '*pr'of 'a1*2^JS_LIMB_BITS+a0 + / d' with 0 <= a1 < d. */ +static inline js_limb_t js_udiv1norm(js_limb_t *pr, js_limb_t a1, js_limb_t a0, + js_limb_t d, js_limb_t d_inv) +{ + js_limb_t n1m, n_adj, q, r, ah; + js_dlimb_t a; + n1m = ((js_slimb_t)a0 >> (JS_LIMB_BITS - 1)); + n_adj = a0 + (n1m & d); + a = (js_dlimb_t)d_inv * (a1 - n1m) + n_adj; + q = (a >> JS_LIMB_BITS) + a1; + /* compute a - q * r and update q so that the remainder is\ + between 0 and d - 1 */ + a = ((js_dlimb_t)a1 << JS_LIMB_BITS) | a0; + a = a - (js_dlimb_t)q * d - d; + ah = a >> JS_LIMB_BITS; + q += 1 + ah; + r = (js_limb_t)a + (ah & d); + *pr = r; + return q; +} + +#define UDIV1NORM_THRESHOLD 3 + +/* b must be >= 1 << (JS_LIMB_BITS - 1) */ +static js_limb_t js_mp_div1norm(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n, + js_limb_t b, js_limb_t r) +{ + js_slimb_t i; + + if (n >= UDIV1NORM_THRESHOLD) { + js_limb_t b_inv; + b_inv = js_udiv1norm_init(b); + for(i = n - 1; i >= 0; i--) { + tabr[i] = js_udiv1norm(&r, r, taba[i], b, b_inv); + } + } else { + js_dlimb_t a1; + for(i = n - 1; i >= 0; i--) { + a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i]; + tabr[i] = a1 / b; + r = a1 % b; + } + } + return r; +} + +/* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb + - 1] must be >= 1 << (JS_LIMB_BITS - 1). na - nb must be >= 0. 'taba' + is modified and contains the remainder (nb limbs). tabq[0..na-nb] + contains the quotient with tabq[na - nb] <= 1. */ +static void js_mp_divnorm(js_limb_t *tabq, js_limb_t *taba, js_limb_t na, + const js_limb_t *tabb, js_limb_t nb) +{ + js_limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r; + int i, j; + + b1 = tabb[nb - 1]; + if (nb == 1) { + taba[0] = js_mp_div1norm(tabq, taba, na, b1, 0); + return; + } + n = na - nb; + + if (n >= UDIV1NORM_THRESHOLD) + b1_inv = js_udiv1norm_init(b1); + else + b1_inv = 0; + + /* first iteration: the quotient is only 0 or 1 */ + q = 1; + for(j = nb - 1; j >= 0; j--) { + if (taba[n + j] != tabb[j]) { + if (taba[n + j] < tabb[j]) + q = 0; + break; + } + } + tabq[n] = q; + if (q) { + js_mp_sub(taba + n, taba + n, tabb, nb, 0); + } + + for(i = n - 1; i >= 0; i--) { + if (unlikely(taba[i + nb] >= b1)) { + q = -1; + } else if (b1_inv) { + q = js_udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv); + } else { + js_dlimb_t al; + al = ((js_dlimb_t)taba[i + nb] << JS_LIMB_BITS) | taba[i + nb - 1]; + q = al / b1; + r = al % b1; + } + r = js_mp_sub_mul1(taba + i, tabb, nb, q); + + v = taba[i + nb]; + a = v - r; + c = (a > v); + taba[i + nb] = a; + + if (c != 0) { + /* negative result */ + for(;;) { + q--; + c = js_mp_add(taba + i, taba + i, tabb, nb, 0); + /* propagate carry and test if positive result */ + if (c != 0) { + if (++taba[i + nb] == 0) { + break; + } + } + } + } + tabq[i] = q; + } +} + +/* 1 <= shift <= JS_LIMB_BITS - 1 */ +static js_limb_t js_mp_shl(js_limb_t *tabr, const js_limb_t *taba, int n, + int shift) +{ + int i; + js_limb_t l, v; + l = 0; + for(i = 0; i < n; i++) { + v = taba[i]; + tabr[i] = (v << shift) | l; + l = v >> (JS_LIMB_BITS - shift); + } + return l; +} + +/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). + 1 <= shift <= LIMB_BITS - 1 */ +static js_limb_t js_mp_shr(js_limb_t *tab_r, const js_limb_t *tab, int n, + int shift, js_limb_t high) +{ + int i; + js_limb_t l, a; + + l = high; + for(i = n - 1; i >= 0; i--) { + a = tab[i]; + tab_r[i] = (a >> shift) | (l << (JS_LIMB_BITS - shift)); + l = a; + } + return l & (((js_limb_t)1 << shift) - 1); +} + +static JSBigInt *js_bigint_new(JSContext *ctx, int len) +{ + JSBigInt *r; + if (len > JS_BIGINT_MAX_SIZE) { + JS_ThrowRangeError(ctx, "BigInt is too large to allocate"); + return NULL; + } + r = js_malloc(ctx, sizeof(JSBigInt) + len * sizeof(js_limb_t)); + if (!r) + return NULL; + r->header.ref_count = 1; + r->len = len; + return r; +} + +static JSBigInt *js_bigint_set_si(JSBigIntBuf *buf, js_slimb_t a) +{ + JSBigInt *r = (JSBigInt *)buf->big_int_buf; + r->header.ref_count = 0; /* fail safe */ + r->len = 1; + r->tab[0] = a; + return r; +} + +static JSBigInt *js_bigint_set_si64(JSBigIntBuf *buf, int64_t a) +{ + JSBigInt *r = (JSBigInt *)buf->big_int_buf; + r->header.ref_count = 0; /* fail safe */ + if (a >= INT32_MIN && a <= INT32_MAX) { + r->len = 1; + r->tab[0] = a; + } else { + r->len = 2; + r->tab[0] = a; + r->tab[1] = a >> JS_LIMB_BITS; + } + return r; +} + +/* val must be a short big int */ +static JSBigInt *js_bigint_set_short(JSBigIntBuf *buf, JSValueConst val) +{ + return js_bigint_set_si(buf, JS_VALUE_GET_SHORT_BIG_INT(val)); +} + +static __maybe_unused void js_bigint_dump1(JSContext *ctx, const char *str, + const js_limb_t *tab, int len) +{ + int i; + printf("%s: ", str); + for(i = len - 1; i >= 0; i--) { + printf(" %08x", tab[i]); + } + printf("\n"); +} + +static __maybe_unused void js_bigint_dump(JSContext *ctx, const char *str, + const JSBigInt *p) +{ + js_bigint_dump1(ctx, str, p->tab, p->len); +} + +static JSBigInt *js_bigint_new_si(JSContext *ctx, js_slimb_t a) +{ + JSBigInt *r; + r = js_bigint_new(ctx, 1); + if (!r) + return NULL; + r->tab[0] = a; + return r; +} + +static JSBigInt *js_bigint_new_si64(JSContext *ctx, int64_t a) +{ + if (a >= INT32_MIN && a <= INT32_MAX) { + return js_bigint_new_si(ctx, a); + } else { + JSBigInt *r; + r = js_bigint_new(ctx, 2); + if (!r) + return NULL; + r->tab[0] = a; + r->tab[1] = a >> 32; + return r; + } +} + +static JSBigInt *js_bigint_new_ui64(JSContext *ctx, uint64_t a) +{ + if (a <= INT64_MAX) { + return js_bigint_new_si64(ctx, a); + } else { + JSBigInt *r; + r = js_bigint_new(ctx, (65 + JS_LIMB_BITS - 1) / JS_LIMB_BITS); + if (!r) + return NULL; + r->tab[0] = a; + r->tab[1] = a >> 32; + r->tab[2] = 0; + return r; + } +} + +static JSBigInt *js_bigint_new_di(JSContext *ctx, js_sdlimb_t a) +{ + JSBigInt *r; + if (a == (js_slimb_t)a) { + r = js_bigint_new(ctx, 1); + if (!r) + return NULL; + r->tab[0] = a; + } else { + r = js_bigint_new(ctx, 2); + if (!r) + return NULL; + r->tab[0] = a; + r->tab[1] = a >> JS_LIMB_BITS; + } + return r; +} + +/* Remove redundant high order limbs. Warning: 'a' may be + reallocated. Can never fail. +*/ +static JSBigInt *js_bigint_normalize1(JSContext *ctx, JSBigInt *a, int l) +{ + js_limb_t v; + + assert(a->header.ref_count == 1); + while (l > 1) { + v = a->tab[l - 1]; + if ((v != 0 && v != -1) || + (v & 1) != (a->tab[l - 2] >> (JS_LIMB_BITS - 1))) { + break; + } + l--; + } + if (l != a->len) { + JSBigInt *a1; + /* realloc to reduce the size */ + a->len = l; + a1 = js_realloc(ctx, a, sizeof(JSBigInt) + l * sizeof(js_limb_t)); + if (a1) + a = a1; + } + return a; +} + +static JSBigInt *js_bigint_normalize(JSContext *ctx, JSBigInt *a) +{ + return js_bigint_normalize1(ctx, a, a->len); +} + +/* return 0 or 1 depending on the sign */ +static inline int js_bigint_sign(const JSBigInt *a) +{ + return a->tab[a->len - 1] >> (JS_LIMB_BITS - 1); +} + +static js_slimb_t js_bigint_get_si_sat(const JSBigInt *a) +{ + if (a->len == 1) { + return a->tab[0]; + } else { + if (js_bigint_sign(a)) + return INT32_MIN; + else + return INT32_MAX; + } +} + +/* add the op1 limb */ +static JSBigInt *js_bigint_extend(JSContext *ctx, JSBigInt *r, + js_limb_t op1) +{ + int n2 = r->len; + if ((op1 != 0 && op1 != -1) || + (op1 & 1) != r->tab[n2 - 1] >> (JS_LIMB_BITS - 1)) { + JSBigInt *r1; + r1 = js_realloc(ctx, r, + sizeof(JSBigInt) + (n2 + 1) * sizeof(js_limb_t)); + if (!r1) { + js_free(ctx, r); + return NULL; + } + r = r1; + r->len = n2 + 1; + r->tab[n2] = op1; + } else { + /* otherwise still need to normalize the result */ + r = js_bigint_normalize(ctx, r); + } + return r; +} + +/* return NULL in case of error. Compute a + b (b_neg = 0) or a - b + (b_neg = 1) */ +/* XXX: optimize */ +static JSBigInt *js_bigint_add(JSContext *ctx, const JSBigInt *a, + const JSBigInt *b, int b_neg) +{ + JSBigInt *r; + int n1, n2, i; + js_limb_t carry, op1, op2, a_sign, b_sign; + + n2 = max_int(a->len, b->len); + n1 = min_int(a->len, b->len); + r = js_bigint_new(ctx, n2); + if (!r) + return NULL; + /* XXX: optimize */ + /* common part */ + carry = b_neg; + for(i = 0; i < n1; i++) { + op1 = a->tab[i]; + op2 = b->tab[i] ^ (-b_neg); + ADDC(r->tab[i], carry, op1, op2, carry); + } + a_sign = -js_bigint_sign(a); + b_sign = (-js_bigint_sign(b)) ^ (-b_neg); + /* part with sign extension of one operand */ + if (a->len > b->len) { + for(i = n1; i < n2; i++) { + op1 = a->tab[i]; + ADDC(r->tab[i], carry, op1, b_sign, carry); + } + } else if (a->len < b->len) { + for(i = n1; i < n2; i++) { + op2 = b->tab[i] ^ (-b_neg); + ADDC(r->tab[i], carry, a_sign, op2, carry); + } + } + + /* part with sign extension for both operands. Extend the result + if necessary */ + return js_bigint_extend(ctx, r, a_sign + b_sign + carry); +} + +/* XXX: optimize */ +static JSBigInt *js_bigint_neg(JSContext *ctx, const JSBigInt *a) +{ + JSBigIntBuf buf; + JSBigInt *b; + b = js_bigint_set_si(&buf, 0); + return js_bigint_add(ctx, b, a, 1); +} + +static JSBigInt *js_bigint_mul(JSContext *ctx, const JSBigInt *a, + const JSBigInt *b) +{ + JSBigInt *r; + + r = js_bigint_new(ctx, a->len + b->len); + if (!r) + return NULL; + js_mp_mul_basecase(r->tab, a->tab, a->len, b->tab, b->len); + /* correct the result if negative operands (no overflow is + possible) */ + if (js_bigint_sign(a)) + js_mp_sub(r->tab + a->len, r->tab + a->len, b->tab, b->len, 0); + if (js_bigint_sign(b)) + js_mp_sub(r->tab + b->len, r->tab + b->len, a->tab, a->len, 0); + return js_bigint_normalize(ctx, r); +} + +/* return the division or the remainder. 'b' must be != 0. return NULL + in case of exception (division by zero or memory error) */ +static JSBigInt *js_bigint_divrem(JSContext *ctx, const JSBigInt *a, + const JSBigInt *b, bool is_rem) +{ + JSBigInt *r, *q; + js_limb_t *tabb, h; + int na, nb, a_sign, b_sign, shift; + + if (b->len == 1 && b->tab[0] == 0) { + JS_ThrowRangeError(ctx, "BigInt division by zero"); + return NULL; + } + + a_sign = js_bigint_sign(a); + b_sign = js_bigint_sign(b); + na = a->len; + nb = b->len; + + r = js_bigint_new(ctx, na + 2); + if (!r) + return NULL; + if (a_sign) { + js_mp_neg(r->tab, a->tab, na); + } else { + memcpy(r->tab, a->tab, na * sizeof(a->tab[0])); + } + /* normalize */ + while (na > 1 && r->tab[na - 1] == 0) + na--; + + tabb = js_malloc(ctx, nb * sizeof(tabb[0])); + if (!tabb) { + js_free(ctx, r); + return NULL; + } + if (b_sign) { + js_mp_neg(tabb, b->tab, nb); + } else { + memcpy(tabb, b->tab, nb * sizeof(tabb[0])); + } + /* normalize */ + while (nb > 1 && tabb[nb - 1] == 0) + nb--; + + /* trivial case if 'a' is small */ + if (na < nb) { + js_free(ctx, r); + js_free(ctx, tabb); + if (is_rem) { + /* r = a */ + r = js_bigint_new(ctx, a->len); + if (!r) + return NULL; + memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0])); + return r; + } else { + /* q = 0 */ + return js_bigint_new_si(ctx, 0); + } + } + + /* normalize 'b' */ + shift = js_limb_clz(tabb[nb - 1]); + if (shift != 0) { + js_mp_shl(tabb, tabb, nb, shift); + h = js_mp_shl(r->tab, r->tab, na, shift); + if (h != 0) + r->tab[na++] = h; + } + + q = js_bigint_new(ctx, na - nb + 2); /* one more limb for the sign */ + if (!q) { + js_free(ctx, r); + js_free(ctx, tabb); + return NULL; + } + + // js_bigint_dump1(ctx, "a", r->tab, na); + // js_bigint_dump1(ctx, "b", tabb, nb); + js_mp_divnorm(q->tab, r->tab, na, tabb, nb); + js_free(ctx, tabb); + + if (is_rem) { + js_free(ctx, q); + if (shift != 0) + js_mp_shr(r->tab, r->tab, nb, shift, 0); + r->tab[nb++] = 0; + if (a_sign) + js_mp_neg(r->tab, r->tab, nb); + r = js_bigint_normalize1(ctx, r, nb); + return r; + } else { + js_free(ctx, r); + q->tab[na - nb + 1] = 0; + if (a_sign ^ b_sign) { + js_mp_neg(q->tab, q->tab, q->len); + } + q = js_bigint_normalize(ctx, q); + return q; + } +} + +/* and, or, xor */ +static JSBigInt *js_bigint_logic(JSContext *ctx, const JSBigInt *a, + const JSBigInt *b, OPCodeEnum op) +{ + JSBigInt *r; + js_limb_t b_sign; + int a_len, b_len, i; + + if (a->len < b->len) { + const JSBigInt *tmp; + tmp = a; + a = b; + b = tmp; + } + /* a_len >= b_len */ + a_len = a->len; + b_len = b->len; + b_sign = -js_bigint_sign(b); + + r = js_bigint_new(ctx, a_len); + if (!r) + return NULL; + switch(op) { + case OP_or: + for(i = 0; i < b_len; i++) { + r->tab[i] = a->tab[i] | b->tab[i]; + } + for(i = b_len; i < a_len; i++) { + r->tab[i] = a->tab[i] | b_sign; + } + break; + case OP_and: + for(i = 0; i < b_len; i++) { + r->tab[i] = a->tab[i] & b->tab[i]; + } + for(i = b_len; i < a_len; i++) { + r->tab[i] = a->tab[i] & b_sign; + } + break; + case OP_xor: + for(i = 0; i < b_len; i++) { + r->tab[i] = a->tab[i] ^ b->tab[i]; + } + for(i = b_len; i < a_len; i++) { + r->tab[i] = a->tab[i] ^ b_sign; + } + break; + default: + abort(); + } + return js_bigint_normalize(ctx, r); +} + +static JSBigInt *js_bigint_not(JSContext *ctx, const JSBigInt *a) +{ + JSBigInt *r; + int i; + + r = js_bigint_new(ctx, a->len); + if (!r) + return NULL; + for(i = 0; i < a->len; i++) { + r->tab[i] = ~a->tab[i]; + } + /* no normalization is needed */ + return r; +} + +static JSBigInt *js_bigint_shl(JSContext *ctx, const JSBigInt *a, + unsigned int shift1) +{ + int d, i, shift; + JSBigInt *r; + js_limb_t l; + + if (a->len == 1 && a->tab[0] == 0) + return js_bigint_new_si(ctx, 0); /* zero case */ + d = shift1 / JS_LIMB_BITS; + shift = shift1 % JS_LIMB_BITS; + r = js_bigint_new(ctx, a->len + d); + if (!r) + return NULL; + for(i = 0; i < d; i++) + r->tab[i] = 0; + if (shift == 0) { + for(i = 0; i < a->len; i++) { + r->tab[i + d] = a->tab[i]; + } + } else { + l = js_mp_shl(r->tab + d, a->tab, a->len, shift); + if (js_bigint_sign(a)) + l |= (js_limb_t)(-1) << shift; + r = js_bigint_extend(ctx, r, l); + } + return r; +} + +static JSBigInt *js_bigint_shr(JSContext *ctx, const JSBigInt *a, + unsigned int shift1) +{ + int d, i, shift, a_sign, n1; + JSBigInt *r; + + d = shift1 / JS_LIMB_BITS; + shift = shift1 % JS_LIMB_BITS; + a_sign = js_bigint_sign(a); + if (d >= a->len) + return js_bigint_new_si(ctx, -a_sign); + n1 = a->len - d; + r = js_bigint_new(ctx, n1); + if (!r) + return NULL; + if (shift == 0) { + for(i = 0; i < n1; i++) { + r->tab[i] = a->tab[i + d]; + } + /* no normalization is needed */ + } else { + js_mp_shr(r->tab, a->tab + d, n1, shift, -a_sign); + r = js_bigint_normalize(ctx, r); + } + return r; +} + +static JSBigInt *js_bigint_pow(JSContext *ctx, const JSBigInt *a, JSBigInt *b) +{ + uint32_t e; + int n_bits, i; + JSBigInt *r, *r1; + + /* b must be >= 0 */ + if (js_bigint_sign(b)) { + JS_ThrowRangeError(ctx, "BigInt negative exponent"); + return NULL; + } + if (b->len == 1 && b->tab[0] == 0) { + /* a^0 = 1 */ + return js_bigint_new_si(ctx, 1); + } else if (a->len == 1) { + js_limb_t v; + bool is_neg; + + v = a->tab[0]; + if (v <= 1) + return js_bigint_new_si(ctx, v); + else if (v == -1) + return js_bigint_new_si(ctx, 1 - 2 * (b->tab[0] & 1)); + is_neg = (js_slimb_t)v < 0; + if (is_neg) + v = -v; + if ((v & (v - 1)) == 0) { + uint64_t e1; + int n; + /* v = 2^n */ + n = JS_LIMB_BITS - 1 - js_limb_clz(v); + if (b->len > 1) + goto overflow; + if (b->tab[0] > INT32_MAX) + goto overflow; + e = b->tab[0]; + e1 = (uint64_t)e * n; + if (e1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS) + goto overflow; + e = e1; + if (is_neg) + is_neg = b->tab[0] & 1; + r = js_bigint_new(ctx, + (e + JS_LIMB_BITS + 1 - is_neg) / JS_LIMB_BITS); + if (!r) + return NULL; + memset(r->tab, 0, sizeof(r->tab[0]) * r->len); + r->tab[e / JS_LIMB_BITS] = + (js_limb_t)(1 - 2 * is_neg) << (e % JS_LIMB_BITS); + return r; + } + } + if (b->len > 1) + goto overflow; + if (b->tab[0] > INT32_MAX) + goto overflow; + e = b->tab[0]; + n_bits = 32 - clz32(e); + + r = js_bigint_new(ctx, a->len); + if (!r) + return NULL; + memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0])); + for(i = n_bits - 2; i >= 0; i--) { + r1 = js_bigint_mul(ctx, r, r); + if (!r1) + return NULL; + js_free(ctx, r); + r = r1; + if ((e >> i) & 1) { + r1 = js_bigint_mul(ctx, r, a); + if (!r1) + return NULL; + js_free(ctx, r); + r = r1; + } + } + return r; + overflow: + JS_ThrowRangeError(ctx, "BigInt is too large"); + return NULL; +} + +/* return (mant, exp) so that abs(a) ~ mant*2^(exp - (limb_bits - + 1). a must be != 0. */ +static uint64_t js_bigint_get_mant_exp(JSContext *ctx, + int *pexp, const JSBigInt *a) +{ + js_limb_t t[4 - JS_LIMB_BITS / 32], carry, v, low_bits; + int n1, n2, sgn, shift, i, j, e; + uint64_t a1, a0; + + n2 = 4 - JS_LIMB_BITS / 32; + n1 = a->len - n2; + sgn = js_bigint_sign(a); + + /* low_bits != 0 if there are a non zero low bit in abs(a) */ + low_bits = 0; + carry = sgn; + for(i = 0; i < n1; i++) { + v = (a->tab[i] ^ (-sgn)) + carry; + carry = v < carry; + low_bits |= v; + } + /* get the n2 high limbs of abs(a) */ + for(j = 0; j < n2; j++) { + i = j + n1; + if (i < 0) { + v = 0; + } else { + v = (a->tab[i] ^ (-sgn)) + carry; + carry = v < carry; + } + t[j] = v; + } + + a1 = ((uint64_t)t[2] << 32) | t[1]; + a0 = (uint64_t)t[0] << 32; + a0 |= (low_bits != 0); + /* normalize */ + { + shift = clz64(a1); + if (shift != 0) { + a1 = (a1 << shift) | (a0 >> (64 - shift)); + a0 <<= shift; + } + } + a1 |= (a0 != 0); /* keep the bits for the final rounding */ + /* compute the exponent */ + e = a->len * JS_LIMB_BITS - shift - 1; + *pexp = e; + return a1; +} + +/* shift left with round to nearest, ties to even. n >= 1 */ +static uint64_t shr_rndn(uint64_t a, int n) +{ + uint64_t addend = ((a >> n) & 1) + ((1 << (n - 1)) - 1); + return (a + addend) >> n; +} + +/* convert to float64 with round to nearest, ties to even. Return + +/-infinity if too large. */ +static double js_bigint_to_float64(JSContext *ctx, const JSBigInt *a) +{ + int sgn, e; + uint64_t mant; + + if (a->len == 1) { + /* fast case, including zero */ + return (double)(js_slimb_t)a->tab[0]; + } + + sgn = js_bigint_sign(a); + mant = js_bigint_get_mant_exp(ctx, &e, a); + if (e > 1023) { + /* overflow: return infinity */ + mant = 0; + e = 1024; + } else { + mant = (mant >> 1) | (mant & 1); /* avoid overflow in rounding */ + mant = shr_rndn(mant, 10); + /* rounding can cause an overflow */ + if (mant >= ((uint64_t)1 << 53)) { + mant >>= 1; + e++; + } + mant &= (((uint64_t)1 << 52) - 1); + } + return uint64_as_float64(((uint64_t)sgn << 63) | + ((uint64_t)(e + 1023) << 52) | + mant); +} + +/* return (1, NULL) if not an integer, (2, NULL) if NaN or Infinity, + (0, n) if an integer, (0, NULL) in case of memory error */ +static JSBigInt *js_bigint_from_float64(JSContext *ctx, int *pres, double a1) +{ + uint64_t a = float64_as_uint64(a1); + int sgn, e, shift; + uint64_t mant; + JSBigIntBuf buf; + JSBigInt *r; + + sgn = a >> 63; + e = (a >> 52) & ((1 << 11) - 1); + mant = a & (((uint64_t)1 << 52) - 1); + if (e == 2047) { + /* NaN, Infinity */ + *pres = 2; + return NULL; + } + if (e == 0 && mant == 0) { + /* zero */ + *pres = 0; + return js_bigint_new_si(ctx, 0); + } + e -= 1023; + /* 0 < a < 1 : not an integer */ + if (e < 0) + goto not_an_integer; + mant |= (uint64_t)1 << 52; + if (e < 52) { + shift = 52 - e; + /* check that there is no fractional part */ + if (mant & (((uint64_t)1 << shift) - 1)) { + not_an_integer: + *pres = 1; + return NULL; + } + mant >>= shift; + e = 0; + } else { + e -= 52; + } + if (sgn) + mant = -mant; + /* the integer is mant*2^e */ + r = js_bigint_set_si64(&buf, (int64_t)mant); + *pres = 0; + return js_bigint_shl(ctx, r, e); +} + +/* return -1, 0, 1 or (2) (unordered) */ +static int js_bigint_float64_cmp(JSContext *ctx, const JSBigInt *a, + double b) +{ + int b_sign, a_sign, e, f; + uint64_t mant, b1, a_mant; + + b1 = float64_as_uint64(b); + b_sign = b1 >> 63; + e = (b1 >> 52) & ((1 << 11) - 1); + mant = b1 & (((uint64_t)1 << 52) - 1); + a_sign = js_bigint_sign(a); + if (e == 2047) { + if (mant != 0) { + /* NaN */ + return 2; + } else { + /* +/- infinity */ + return 2 * b_sign - 1; + } + } else if (e == 0 && mant == 0) { + /* b = +/-0 */ + if (a->len == 1 && a->tab[0] == 0) + return 0; + else + return 1 - 2 * a_sign; + } else if (a->len == 1 && a->tab[0] == 0) { + /* a = 0, b != 0 */ + return 2 * b_sign - 1; + } else if (a_sign != b_sign) { + return 1 - 2 * a_sign; + } else { + e -= 1023; + /* Note: handling denormals is not necessary because we + compare to integers hence f >= 0 */ + /* compute f so that 2^f <= abs(a) < 2^(f+1) */ + a_mant = js_bigint_get_mant_exp(ctx, &f, a); + if (f != e) { + if (f < e) + return -1; + else + return 1; + } else { + mant = (mant | ((uint64_t)1 << 52)) << 11; /* align to a_mant */ + if (a_mant < mant) + return 2 * a_sign - 1; + else if (a_mant > mant) + return 1 - 2 * a_sign; + else + return 0; + } + } +} + +/* return -1, 0 or 1 */ +static int js_bigint_cmp(JSContext *ctx, const JSBigInt *a, + const JSBigInt *b) +{ + int a_sign, b_sign, res, i; + a_sign = js_bigint_sign(a); + b_sign = js_bigint_sign(b); + if (a_sign != b_sign) { + res = 1 - 2 * a_sign; + } else { + /* we assume the numbers are normalized */ + if (a->len != b->len) { + if (a->len < b->len) + res = 2 * a_sign - 1; + else + res = 1 - 2 * a_sign; + } else { + res = 0; + for(i = a->len -1; i >= 0; i--) { + if (a->tab[i] != b->tab[i]) { + if (a->tab[i] < b->tab[i]) + res = -1; + else + res = 1; + break; + } + } + } + } + return res; +} + +/* contains 10^i */ +static const js_limb_t js_pow_dec[JS_LIMB_DIGITS + 1] = { + 1U, + 10U, + 100U, + 1000U, + 10000U, + 100000U, + 1000000U, + 10000000U, + 100000000U, + 1000000000U, +}; + +/* syntax: [-]digits in base radix. Return NULL if memory error. radix + = 10, 2, 8 or 16. */ +static JSBigInt *js_bigint_from_string(JSContext *ctx, + const char *str, int radix) +{ + const char *p = str; + size_t n_digits1; + int is_neg, n_digits, n_limbs, len, log2_radix, n_bits, i; + JSBigInt *r; + js_limb_t v, c, h; + + is_neg = 0; + if (*p == '-') { + is_neg = 1; + p++; + } + while (*p == '0') + p++; + n_digits1 = strlen(p); + /* the real check for overflox is done js_bigint_new(). Here + we just avoid integer overflow */ + if (n_digits1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS) { + JS_ThrowRangeError(ctx, "BigInt is too large to allocate"); + return NULL; + } + n_digits = n_digits1; + log2_radix = 32 - clz32(radix - 1); /* ceil(log2(radix)) */ + /* compute the maximum number of limbs */ + if (radix == 10) { + n_bits = (n_digits * 27 + 7) / 8; /* >= ceil(n_digits * log2(10)) */ + } else { + n_bits = n_digits * log2_radix; + } + /* we add one extra bit for the sign */ + n_limbs = max_int(1, n_bits / JS_LIMB_BITS + 1); + r = js_bigint_new(ctx, n_limbs); + if (!r) + return NULL; + if (radix == 10) { + int digits_per_limb = JS_LIMB_DIGITS; + len = 1; + r->tab[0] = 0; + for(;;) { + /* XXX: slow */ + v = 0; + for(i = 0; i < digits_per_limb; i++) { + c = js_to_digit(*p); + if (c >= radix) + break; + p++; + v = v * 10 + c; + } + if (i == 0) + break; + if (len == 1 && r->tab[0] == 0) { + r->tab[0] = v; + } else { + h = js_mp_mul1(r->tab, r->tab, len, js_pow_dec[i], v); + if (h != 0) { + r->tab[len++] = h; + } + } + } + /* add one extra limb to have the correct sign*/ + if ((r->tab[len - 1] >> (JS_LIMB_BITS - 1)) != 0) + r->tab[len++] = 0; + r->len = len; + } else { + unsigned int bit_pos, shift, pos; + + /* power of two base: no multiplication is needed */ + r->len = n_limbs; + memset(r->tab, 0, sizeof(r->tab[0]) * n_limbs); + for(i = 0; i < n_digits; i++) { + c = js_to_digit(p[n_digits - 1 - i]); + assert(c < radix); + bit_pos = i * log2_radix; + shift = bit_pos & (JS_LIMB_BITS - 1); + pos = bit_pos / JS_LIMB_BITS; + r->tab[pos] |= c << shift; + /* if log2_radix does not divide JS_LIMB_BITS, needed an + additional op */ + if (shift + log2_radix > JS_LIMB_BITS) { + r->tab[pos + 1] |= c >> (JS_LIMB_BITS - shift); + } + } + } + r = js_bigint_normalize(ctx, r); + /* XXX: could do it in place */ + if (is_neg) { + JSBigInt *r1; + r1 = js_bigint_neg(ctx, r); + js_free(ctx, r); + r = r1; + } + return r; +} + +/* 2 <= base <= 36 */ +static char const digits[36] = { + '0','1','2','3','4','5','6','7','8','9', + 'a','b','c','d','e','f','g','h','i','j', + 'k','l','m','n','o','p','q','r','s','t', + 'u','v','w','x','y','z' +}; + +/* special version going backwards */ +/* XXX: use dtoa.c */ +static char *js_u64toa(char *q, int64_t n, unsigned int base) +{ + int digit; + if (base == 10) { + /* division by known base uses multiplication */ + do { + digit = (uint64_t)n % 10; + n = (uint64_t)n / 10; + *--q = '0' + digit; + } while (n != 0); + } else { + do { + digit = (uint64_t)n % base; + n = (uint64_t)n / base; + *--q = digits[digit]; + } while (n != 0); + } + return q; +} + +/* len >= 1. 2 <= radix <= 36 */ +static char *js_limb_to_a(char *q, js_limb_t n, unsigned int radix, int len) +{ + int digit, i; + + if (radix == 10) { + /* specific case with constant divisor */ + /* XXX: optimize */ + for(i = 0; i < len; i++) { + digit = (js_limb_t)n % 10; + n = (js_limb_t)n / 10; + *--q = digit + '0'; + } + } else { + for(i = 0; i < len; i++) { + digit = (js_limb_t)n % radix; + n = (js_limb_t)n / radix; + *--q = digits[digit]; + } + } + return q; +} + +#define JS_RADIX_MAX 36 + +static const uint8_t js_digits_per_limb_table[JS_RADIX_MAX - 1] = { +32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +}; + +static const js_limb_t js_radix_base_table[JS_RADIX_MAX - 1] = { + 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395, + 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91, + 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021, + 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571, + 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d, + 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51, + 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899, + 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1, + 0x5c13d840, 0x6d91b519, 0x81bf1000, +}; + +static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix) +{ + if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) { + char buf[66]; + int len; + len = i64toa_radix(buf, JS_VALUE_GET_SHORT_BIG_INT(val), radix); + return js_new_string8_len(ctx, buf, len); + } else { + JSBigInt *r, *tmp = NULL; + char *buf, *q, *buf_end; + int is_neg, n_bits, log2_radix, n_digits; + bool is_binary_radix; + JSValue res; + + assert(JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT); + r = JS_VALUE_GET_PTR(val); + if (r->len == 1 && r->tab[0] == 0) { + /* '0' case */ + return js_new_string8_len(ctx, "0", 1); + } + is_binary_radix = ((radix & (radix - 1)) == 0); + is_neg = js_bigint_sign(r); + if (is_neg) { + tmp = js_bigint_neg(ctx, r); + if (!tmp) + return JS_EXCEPTION; + r = tmp; + } else if (!is_binary_radix) { + /* need to modify 'r' */ + tmp = js_bigint_new(ctx, r->len); + if (!tmp) + return JS_EXCEPTION; + memcpy(tmp->tab, r->tab, r->len * sizeof(r->tab[0])); + r = tmp; + } + log2_radix = 31 - clz32(radix); /* floor(log2(radix)) */ + n_bits = r->len * JS_LIMB_BITS - js_limb_clz(r->tab[r->len - 1]); + /* n_digits is exact only if radix is a power of + two. Otherwise it is >= the exact number of digits */ + n_digits = (n_bits + log2_radix - 1) / log2_radix; + /* XXX: could directly build the JSString */ + buf = js_malloc(ctx, n_digits + is_neg + 1); + if (!buf) { + js_free(ctx, tmp); + return JS_EXCEPTION; + } + q = buf + n_digits + is_neg + 1; + *--q = '\0'; + buf_end = q; + if (!is_binary_radix) { + int len; + js_limb_t radix_base, v; + radix_base = js_radix_base_table[radix - 2]; + len = r->len; + for(;;) { + /* remove leading zero limbs */ + while (len > 1 && r->tab[len - 1] == 0) + len--; + if (len == 1 && r->tab[0] < radix_base) { + v = r->tab[0]; + if (v != 0) { + q = js_u64toa(q, v, radix); + } + break; + } else { + v = js_mp_div1(r->tab, r->tab, len, radix_base, 0); + q = js_limb_to_a(q, v, radix, js_digits_per_limb_table[radix - 2]); + } + } + } else { + int i, shift; + unsigned int bit_pos, pos, c; + + /* radix is a power of two */ + for(i = 0; i < n_digits; i++) { + bit_pos = i * log2_radix; + pos = bit_pos / JS_LIMB_BITS; + shift = bit_pos % JS_LIMB_BITS; + c = r->tab[pos] >> shift; + if ((shift + log2_radix) > JS_LIMB_BITS && + (pos + 1) < r->len) { + c |= r->tab[pos + 1] << (JS_LIMB_BITS - shift); + } + c &= (radix - 1); + *--q = digits[c]; + } + } + if (is_neg) + *--q = '-'; + js_free(ctx, tmp); + res = js_new_string8_len(ctx, q, buf_end - q); + js_free(ctx, buf); + return res; + } +} + +/* if possible transform a BigInt to short big and free it, otherwise + return a normal bigint */ +static JSValue JS_CompactBigInt(JSContext *ctx, JSBigInt *p) +{ + JSValue res; + if (p->len == 1) { + res = __JS_NewShortBigInt(ctx, (js_slimb_t)p->tab[0]); + js_free(ctx, p); + return res; + } else { + return JS_MKPTR(JS_TAG_BIG_INT, p); + } +} + +#define ATOD_INT_ONLY (1 << 0) +/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */ +#define ATOD_ACCEPT_BIN_OCT (1 << 2) +/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */ +#define ATOD_ACCEPT_LEGACY_OCTAL (1 << 4) +/* accept _ between digits as a digit separator */ +#define ATOD_ACCEPT_UNDERSCORES (1 << 5) +/* allow a suffix to override the type */ +#define ATOD_ACCEPT_SUFFIX (1 << 6) +/* default type */ +#define ATOD_TYPE_MASK (3 << 7) +#define ATOD_TYPE_FLOAT64 (0 << 7) +#define ATOD_TYPE_BIG_INT (1 << 7) +/* accept -0x1 */ +#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10) + +/* return an exception in case of memory error. Return JS_NAN if + invalid syntax */ +/* XXX: directly use js_atod() */ +static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, + int radix, int flags) +{ + const char *p, *p_start; + int sep, is_neg; + bool is_float, has_legacy_octal; + int atod_type = flags & ATOD_TYPE_MASK; + char buf1[64], *buf; + int i, j, len; + bool buf_allocated = false; + JSValue val; + JSATODTempMem atod_mem; + + /* optional separator between digits */ + sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256; + has_legacy_octal = false; + + p = str; + p_start = p; + is_neg = 0; + if (p[0] == '+') { + p++; + p_start++; + if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN)) + goto no_radix_prefix; + } else if (p[0] == '-') { + p++; + p_start++; + is_neg = 1; + if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN)) + goto no_radix_prefix; + } + if (p[0] == '0') { + if ((p[1] == 'x' || p[1] == 'X') && + (radix == 0 || radix == 16)) { + p += 2; + radix = 16; + } else if ((p[1] == 'o' || p[1] == 'O') && + radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) { + p += 2; + radix = 8; + } else if ((p[1] == 'b' || p[1] == 'B') && + radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) { + p += 2; + radix = 2; + } else if ((p[1] >= '0' && p[1] <= '9') && + radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) { + int i; + has_legacy_octal = true; + sep = 256; + for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++) + continue; + if (p[i] == '8' || p[i] == '9') + goto no_prefix; + p += 1; + radix = 8; + } else { + goto no_prefix; + } + /* there must be a digit after the prefix */ + if (js_to_digit((uint8_t)*p) >= radix) + goto fail; + no_prefix: ; + } else { + no_radix_prefix: + if (!(flags & ATOD_INT_ONLY) && + (atod_type == ATOD_TYPE_FLOAT64) && + js__strstart(p, "Infinity", &p)) { + double d = INF; + if (is_neg) + d = -d; + val = js_float64(d); + goto done; + } + } + if (radix == 0) + radix = 10; + is_float = false; + p_start = p; + while (js_to_digit((uint8_t)*p) < radix + || (*p == sep && (radix != 10 || + p != p_start + 1 || p[-1] != '0') && + js_to_digit((uint8_t)p[1]) < radix)) { + p++; + } + if (!(flags & ATOD_INT_ONLY) && radix == 10) { + if (*p == '.' && (p > p_start || js_to_digit((uint8_t)p[1]) < radix)) { + is_float = true; + p++; + if (*p == sep) + goto fail; + while (js_to_digit((uint8_t)*p) < radix || + (*p == sep && js_to_digit((uint8_t)p[1]) < radix)) + p++; + } + if (p > p_start && (*p == 'e' || *p == 'E')) { + const char *p1 = p + 1; + is_float = true; + if (*p1 == '+') { + p1++; + } else if (*p1 == '-') { + p1++; + } + if (is_digit((uint8_t)*p1)) { + p = p1 + 1; + while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1]))) + p++; + } + } + } + if (p == p_start) + goto fail; + + buf = buf1; + buf_allocated = false; + len = p - p_start; + if (unlikely((len + 2) > sizeof(buf1))) { + buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */ + if (!buf) + goto mem_error; + buf_allocated = true; + } + /* remove the separators and the radix prefixes */ + j = 0; + if (is_neg) + buf[j++] = '-'; + for (i = 0; i < len; i++) { + if (p_start[i] != '_') + buf[j++] = p_start[i]; + } + buf[j] = '\0'; + + if (flags & ATOD_ACCEPT_SUFFIX) { + if (*p == 'n') { + p++; + atod_type = ATOD_TYPE_BIG_INT; + } + } + + switch(atod_type) { + case ATOD_TYPE_FLOAT64: + { + double d; + d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY, + &atod_mem); + /* return int or float64 */ + val = js_number(d); + } + break; + case ATOD_TYPE_BIG_INT: + { + JSBigInt *r; + if (has_legacy_octal || is_float) + goto fail; + r = js_bigint_from_string(ctx, buf, radix); + if (!r) { + val = JS_EXCEPTION; + goto done; + } + val = JS_CompactBigInt(ctx, r); + } + break; + default: + abort(); + } + +done: + if (buf_allocated) + js_free_rt(ctx->rt, buf); + if (pp) + *pp = p; + return val; + fail: + val = JS_NAN; + goto done; + mem_error: + val = JS_ThrowOutOfMemory(ctx); + goto done; +} + +typedef enum JSToNumberHintEnum { + TON_FLAG_NUMBER, + TON_FLAG_NUMERIC, +} JSToNumberHintEnum; + +static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, + JSToNumberHintEnum flag) +{ + uint32_t tag; + JSValue ret; + + redo: + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_BIG_INT: + case JS_TAG_SHORT_BIG_INT: + if (flag != TON_FLAG_NUMERIC) { + JS_FreeValue(ctx, val); + return JS_ThrowTypeError(ctx, "cannot convert BigInt to number"); + } + ret = val; + break; + case JS_TAG_FLOAT64: + case JS_TAG_INT: + case JS_TAG_EXCEPTION: + ret = val; + break; + case JS_TAG_BOOL: + case JS_TAG_NULL: + ret = js_int32(JS_VALUE_GET_INT(val)); + break; + case JS_TAG_UNDEFINED: + ret = JS_NAN; + break; + case JS_TAG_OBJECT: + val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); + if (JS_IsException(val)) + return JS_EXCEPTION; + goto redo; + case JS_TAG_STRING: + { + const char *str; + const char *p; + size_t len; + + str = JS_ToCStringLen(ctx, &len, val); + JS_FreeValue(ctx, val); + if (!str) + return JS_EXCEPTION; + p = str; + p += skip_spaces(p); + if ((p - str) == len) { + ret = JS_NewInt32(ctx, 0); + } else { + int flags = ATOD_ACCEPT_BIN_OCT; + ret = js_atof(ctx, p, &p, 0, flags); + if (!JS_IsException(ret)) { + p += skip_spaces(p); + if ((p - str) != len) { + JS_FreeValue(ctx, ret); + ret = JS_NAN; + } + } + } + JS_FreeCString(ctx, str); + } + break; + case JS_TAG_SYMBOL: + JS_FreeValue(ctx, val); + return JS_ThrowTypeError(ctx, "cannot convert symbol to number"); + default: + JS_FreeValue(ctx, val); + ret = JS_NAN; + break; + } + return ret; +} + +static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val) +{ + return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER); +} + +static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val) +{ + return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC); +} + +static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val) +{ + return JS_ToNumericFree(ctx, js_dup(val)); +} + +static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, + JSValue val) +{ + double d; + uint32_t tag; + + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) + goto fail; + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + d = JS_VALUE_GET_INT(val); + break; + case JS_TAG_FLOAT64: + d = JS_VALUE_GET_FLOAT64(val); + break; + default: + abort(); + } + *pres = d; + return 0; +fail: + *pres = NAN; + return -1; +} + +static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val) +{ + uint32_t tag; + + tag = JS_VALUE_GET_TAG(val); + if (tag <= JS_TAG_NULL) { + *pres = JS_VALUE_GET_INT(val); + return 0; + } else if (JS_TAG_IS_FLOAT64(tag)) { + *pres = JS_VALUE_GET_FLOAT64(val); + return 0; + } else { + return __JS_ToFloat64Free(ctx, pres, val); + } +} + +int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val) +{ + return JS_ToFloat64Free(ctx, pres, js_dup(val)); +} + +JSValue JS_ToNumber(JSContext *ctx, JSValueConst val) +{ + return JS_ToNumberFree(ctx, js_dup(val)); +} + +/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */ +static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) +{ + uint32_t tag; + JSValue ret; + + redo: + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + ret = js_int32(JS_VALUE_GET_INT(val)); + break; + case JS_TAG_FLOAT64: + { + double d = JS_VALUE_GET_FLOAT64(val); + if (isnan(d)) { + ret = js_int32(0); + } else { + /* convert -0 to +0 */ + d = trunc(d) + 0.0; + ret = js_number(d); + } + } + break; + default: + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) + return val; + goto redo; + } + return ret; +} + +/* Note: the integer value is satured to 32 bits */ +static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val) +{ + uint32_t tag; + int ret; + + redo: + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + ret = JS_VALUE_GET_INT(val); + break; + case JS_TAG_EXCEPTION: + *pres = 0; + return -1; + case JS_TAG_FLOAT64: + { + double d = JS_VALUE_GET_FLOAT64(val); + if (isnan(d)) { + ret = 0; + } else { + if (d < INT32_MIN) + ret = INT32_MIN; + else if (d > INT32_MAX) + ret = INT32_MAX; + else + ret = (int)d; + } + } + break; + default: + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) { + *pres = 0; + return -1; + } + goto redo; + } + *pres = ret; + return 0; +} + +static int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val) +{ + return JS_ToInt32SatFree(ctx, pres, js_dup(val)); +} + +static int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val, + int min, int max, int min_offset) +{ + int res = JS_ToInt32SatFree(ctx, pres, js_dup(val)); + if (res == 0) { + if (*pres < min) { + *pres += min_offset; + if (*pres < min) + *pres = min; + } else { + if (*pres > max) + *pres = max; + } + } + return res; +} + +static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val) +{ + uint32_t tag; + + redo: + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + *pres = JS_VALUE_GET_INT(val); + return 0; + case JS_TAG_EXCEPTION: + *pres = 0; + return -1; + case JS_TAG_FLOAT64: + { + double d = JS_VALUE_GET_FLOAT64(val); + if (isnan(d)) { + *pres = 0; + } else { + if (d < INT64_MIN) + *pres = INT64_MIN; + else if (d >= 0x1p63) + *pres = INT64_MAX; + else + *pres = (int64_t)d; + } + } + return 0; + default: + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) { + *pres = 0; + return -1; + } + goto redo; + } +} + +int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val) +{ + return JS_ToInt64SatFree(ctx, pres, js_dup(val)); +} + +int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val, + int64_t min, int64_t max, int64_t neg_offset) +{ + int res = JS_ToInt64SatFree(ctx, pres, js_dup(val)); + if (res == 0) { + if (*pres < 0) + *pres += neg_offset; + if (*pres < min) + *pres = min; + else if (*pres > max) + *pres = max; + } + return res; +} + +/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0) + in case of exception */ +static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val) +{ + uint32_t tag; + int64_t ret; + + redo: + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + ret = JS_VALUE_GET_INT(val); + break; + case JS_TAG_FLOAT64: + { + JSFloat64Union u; + double d; + int e; + d = JS_VALUE_GET_FLOAT64(val); + u.d = d; + /* we avoid doing fmod(x, 2^64) */ + e = (u.u64 >> 52) & 0x7ff; + if (likely(e <= (1023 + 62))) { + /* fast case */ + ret = (int64_t)d; + } else if (e <= (1023 + 62 + 53)) { + uint64_t v; + /* remainder modulo 2^64 */ + v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52); + ret = v << ((e - 1023) - 52); + /* take the sign into account */ + if (u.u64 >> 63) + if (ret != INT64_MIN) + ret = -ret; + } else { + ret = 0; /* also handles NaN and +inf */ + } + } + break; + default: + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) { + *pres = 0; + return -1; + } + goto redo; + } + *pres = ret; + return 0; +} + +int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val) +{ + return JS_ToInt64Free(ctx, pres, js_dup(val)); +} + +int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val) +{ + if (JS_IsBigInt(val)) + return JS_ToBigInt64(ctx, pres, val); + else + return JS_ToInt64(ctx, pres, val); +} + +/* return (<0, 0) in case of exception */ +static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val) +{ + uint32_t tag; + int32_t ret; + + redo: + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + ret = JS_VALUE_GET_INT(val); + break; + case JS_TAG_FLOAT64: + { + JSFloat64Union u; + double d; + int e; + d = JS_VALUE_GET_FLOAT64(val); + u.d = d; + /* we avoid doing fmod(x, 2^32) */ + e = (u.u64 >> 52) & 0x7ff; + if (likely(e <= (1023 + 30))) { + /* fast case */ + ret = (int32_t)d; + } else if (e <= (1023 + 30 + 53)) { + uint64_t v; + /* remainder modulo 2^32 */ + v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52); + v = v << ((e - 1023) - 52 + 32); + ret = v >> 32; + /* take the sign into account */ + if (u.u64 >> 63) + if (ret != INT32_MIN) + ret = -ret; + } else { + ret = 0; /* also handles NaN and +inf */ + } + } + break; + default: + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) { + *pres = 0; + return -1; + } + goto redo; + } + *pres = ret; + return 0; +} + +int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val) +{ + return JS_ToInt32Free(ctx, pres, js_dup(val)); +} + +static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val) +{ + return JS_ToInt32Free(ctx, (int32_t *)pres, val); +} + +static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) +{ + uint32_t tag; + int res; + + redo: + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + res = JS_VALUE_GET_INT(val); + res = max_int(0, min_int(255, res)); + break; + case JS_TAG_FLOAT64: + { + double d = JS_VALUE_GET_FLOAT64(val); + if (isnan(d)) { + res = 0; + } else { + if (d < 0) + res = 0; + else if (d > 255) + res = 255; + else + res = lrint(d); + } + } + break; + default: + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) { + *pres = 0; + return -1; + } + goto redo; + } + *pres = res; + return 0; +} + +static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, + JSValue val, bool is_array_ctor) +{ + uint32_t tag, len; + + tag = JS_VALUE_GET_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + { + int v; + v = JS_VALUE_GET_INT(val); + if (v < 0) + goto fail; + len = v; + } + break; + default: + if (JS_TAG_IS_FLOAT64(tag)) { + double d; + d = JS_VALUE_GET_FLOAT64(val); + if (!(d >= 0 && d <= UINT32_MAX)) + goto fail; + len = (uint32_t)d; + if (len != d) + goto fail; + } else { + uint32_t len1; + + if (is_array_ctor) { + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) + return -1; + /* cannot recurse because val is a number */ + if (JS_ToArrayLengthFree(ctx, &len, val, true)) + return -1; + } else { + /* legacy behavior: must do the conversion twice and compare */ + if (JS_ToUint32(ctx, &len, val)) { + JS_FreeValue(ctx, val); + return -1; + } + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) + return -1; + /* cannot recurse because val is a number */ + if (JS_ToArrayLengthFree(ctx, &len1, val, false)) + return -1; + if (len1 != len) { + fail: + JS_ThrowRangeError(ctx, "invalid array length"); + return -1; + } + } + } + break; + } + *plen = len; + return 0; +} + +#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1) + +static bool is_safe_integer(double d) +{ + return isfinite(d) && floor(d) == d && + fabs(d) <= (double)MAX_SAFE_INTEGER; +} + +int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val) +{ + int64_t v; + if (JS_ToInt64Sat(ctx, &v, val)) + return -1; + if (v < 0 || v > MAX_SAFE_INTEGER) { + JS_ThrowRangeError(ctx, "invalid array index"); + *plen = 0; + return -1; + } + *plen = v; + return 0; +} + +/* convert a value to a length between 0 and MAX_SAFE_INTEGER. + return -1 for exception */ +static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen, + JSValue val) +{ + int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0); + JS_FreeValue(ctx, val); + return res; +} + +/* Note: can return an exception */ +static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val) +{ + double d; + if (!JS_IsNumber(val)) + return false; + if (unlikely(JS_ToFloat64(ctx, &d, val))) + return -1; + return isfinite(d) && floor(d) == d; +} + +static bool JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val) +{ + uint32_t tag; + + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + { + int v; + v = JS_VALUE_GET_INT(val); + return (v < 0); + } + case JS_TAG_FLOAT64: + { + JSFloat64Union u; + u.d = JS_VALUE_GET_FLOAT64(val); + return (u.u64 >> 63); + } + case JS_TAG_SHORT_BIG_INT: + return (JS_VALUE_GET_SHORT_BIG_INT(val) < 0); + case JS_TAG_BIG_INT: + { + JSBigInt *p = JS_VALUE_GET_PTR(val); + return js_bigint_sign(p); + } + default: + return false; + } +} + +static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val) +{ + return js_bigint_to_string1(ctx, val, 10); +} + +/*---- floating point number to string conversions ----*/ + +static JSValue js_dtoa2(JSContext *ctx, + double d, int radix, int n_digits, int flags) +{ + char static_buf[128], *buf, *tmp_buf; + int len, len_max; + JSValue res; + JSDTOATempMem dtoa_mem; + len_max = js_dtoa_max_len(d, radix, n_digits, flags); + + /* longer buffer may be used if radix != 10 */ + if (len_max > sizeof(static_buf) - 1) { + tmp_buf = js_malloc(ctx, len_max + 1); + if (!tmp_buf) + return JS_EXCEPTION; + buf = tmp_buf; + } else { + tmp_buf = NULL; + buf = static_buf; + } + len = js_dtoa(buf, d, radix, n_digits, flags, &dtoa_mem); + res = js_new_string8_len(ctx, buf, len); + js_free(ctx, tmp_buf); + return res; +} + +static JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, + int flags) +{ + uint32_t tag; + char buf[32]; + size_t len; + + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_STRING: + return js_dup(val); + case JS_TAG_INT: + len = i32toa(buf, JS_VALUE_GET_INT(val)); + return js_new_string8_len(ctx, buf, len); + case JS_TAG_BOOL: + return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ? + JS_ATOM_true : JS_ATOM_false); + case JS_TAG_NULL: + return JS_AtomToString(ctx, JS_ATOM_null); + case JS_TAG_UNDEFINED: + return JS_AtomToString(ctx, JS_ATOM_undefined); + case JS_TAG_EXCEPTION: + return JS_EXCEPTION; + case JS_TAG_OBJECT: + if (flags & JS_TO_STRING_NO_SIDE_EFFECTS) { + return js_new_string8(ctx, "{}"); + } else { + JSValue val1, ret; + val1 = JS_ToPrimitive(ctx, val, HINT_STRING); + if (JS_IsException(val1)) + return val1; + ret = JS_ToStringInternal(ctx, val1, flags); + JS_FreeValue(ctx, val1); + return ret; + } + break; + case JS_TAG_FUNCTION_BYTECODE: + return js_new_string8(ctx, "[function bytecode]"); + case JS_TAG_SYMBOL: + if (flags & JS_TO_STRING_IS_PROPERTY_KEY) { + return js_dup(val); + } else { + return JS_ThrowTypeError(ctx, "cannot convert symbol to string"); + } + case JS_TAG_FLOAT64: + return js_dtoa2(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0, + JS_DTOA_FORMAT_FREE); + case JS_TAG_SHORT_BIG_INT: + case JS_TAG_BIG_INT: + return js_bigint_to_string(ctx, val); + case JS_TAG_UNINITIALIZED: + return js_new_string8(ctx, "[uninitialized]"); + default: + return js_new_string8(ctx, "[unsupported type]"); + } +} + +JSValue JS_ToString(JSContext *ctx, JSValueConst val) +{ + return JS_ToStringInternal(ctx, val, /*flags*/0); +} + +static JSValue JS_ToStringFree(JSContext *ctx, JSValue val) +{ + JSValue ret; + ret = JS_ToString(ctx, val); + JS_FreeValue(ctx, val); + return ret; +} + +static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val) +{ + if (JS_IsUndefined(val) || JS_IsNull(val)) + return JS_ToStringFree(ctx, val); + return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL); +} + +static JSValue JS_ToPropertyKeyInternal(JSContext *ctx, JSValueConst val, + int flags) +{ + return JS_ToStringInternal(ctx, val, flags | JS_TO_STRING_IS_PROPERTY_KEY); +} + +JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val) +{ + return JS_ToPropertyKeyInternal(ctx, val, /*flags*/0); +} + +static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val) +{ + uint32_t tag = JS_VALUE_GET_TAG(val); + if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) + return JS_ThrowTypeError(ctx, "null or undefined are forbidden"); + return JS_ToString(ctx, val); +} + +static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1) +{ + JSValue val; + JSString *p; + int i; + uint32_t c; + StringBuffer b_s, *b = &b_s; + char buf[16]; + + val = JS_ToStringCheckObject(ctx, val1); + if (JS_IsException(val)) + return val; + p = JS_VALUE_GET_STRING(val); + + if (string_buffer_init(ctx, b, p->len + 2)) + goto fail; + + if (string_buffer_putc8(b, '\"')) + goto fail; + for(i = 0; i < p->len; ) { + c = string_getc(p, &i); + switch(c) { + case '\t': + c = 't'; + goto quote; + case '\r': + c = 'r'; + goto quote; + case '\n': + c = 'n'; + goto quote; + case '\b': + c = 'b'; + goto quote; + case '\f': + c = 'f'; + goto quote; + case '\"': + case '\\': + quote: + if (string_buffer_putc8(b, '\\')) + goto fail; + if (string_buffer_putc8(b, c)) + goto fail; + break; + default: + if (c < 32 || is_surrogate(c)) { + snprintf(buf, sizeof(buf), "\\u%04x", c); + if (string_buffer_write8(b, (uint8_t*)buf, 6)) + goto fail; + } else { + if (string_buffer_putc(b, c)) + goto fail; + } + break; + } + } + if (string_buffer_putc8(b, '\"')) + goto fail; + JS_FreeValue(ctx, val); + return string_buffer_end(b); + fail: + JS_FreeValue(ctx, val); + string_buffer_free(b); + return JS_EXCEPTION; +} + +static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt) +{ + printf("%14s %4s %4s %14s %10s %s\n", + "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS"); +} + +/* for debug only: dump an object without side effect */ +static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) +{ + uint32_t i; + char atom_buf[ATOM_GET_STR_BUF_SIZE]; + JSShape *sh; + JSShapeProperty *prs; + JSProperty *pr; + bool is_first = true; + + /* XXX: should encode atoms with special characters */ + sh = p->shape; /* the shape can be NULL while freeing an object */ + printf("%14p %4d ", + (void *)p, + p->header.ref_count); + if (sh) { + printf("%3d%c %14p ", + sh->header.ref_count, + " *"[sh->is_hashed], + (void *)sh->proto); + } else { + printf("%3s %14s ", "-", "-"); + } + printf("%10s ", + JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name)); + if (p->is_exotic && p->fast_array) { + printf("[ "); + for(i = 0; i < p->u.array.count; i++) { + if (i != 0) + printf(", "); + switch (p->class_id) { + case JS_CLASS_ARRAY: + case JS_CLASS_ARGUMENTS: + JS_DumpValue(rt, p->u.array.u.values[i]); + break; + case JS_CLASS_UINT8C_ARRAY: + case JS_CLASS_INT8_ARRAY: + case JS_CLASS_UINT8_ARRAY: + case JS_CLASS_INT16_ARRAY: + case JS_CLASS_UINT16_ARRAY: + case JS_CLASS_INT32_ARRAY: + case JS_CLASS_UINT32_ARRAY: + case JS_CLASS_BIG_INT64_ARRAY: + case JS_CLASS_BIG_UINT64_ARRAY: + case JS_CLASS_FLOAT16_ARRAY: + case JS_CLASS_FLOAT32_ARRAY: + case JS_CLASS_FLOAT64_ARRAY: + { + int size = 1 << typed_array_size_log2(p->class_id); + const uint8_t *b = p->u.array.u.uint8_ptr + i * size; + while (size-- > 0) + printf("%02X", *b++); + } + break; + } + } + printf(" ] "); + } + + if (sh) { + printf("{ "); + for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { + if (prs->atom != JS_ATOM_NULL) { + pr = &p->prop[i]; + if (!is_first) + printf(", "); + printf("%s: ", + JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom)); + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { + printf("[getset %p %p]", (void *)pr->u.getset.getter, + (void *)pr->u.getset.setter); + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + printf("[varref %p]", (void *)pr->u.var_ref); + } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + printf("[autoinit %p %d %p]", + (void *)js_autoinit_get_realm(pr), + js_autoinit_get_id(pr), + (void *)pr->u.init.opaque); + } else { + JS_DumpValue(rt, pr->u.value); + } + is_first = false; + } + } + printf(" }"); + } + + if (js_class_has_bytecode(p->class_id)) { + JSFunctionBytecode *b = p->u.func.function_bytecode; + JSVarRef **var_refs; + if (b->closure_var_count) { + var_refs = p->u.func.var_refs; + printf(" Closure:"); + for(i = 0; i < b->closure_var_count; i++) { + printf(" "); + JS_DumpValue(rt, var_refs[i]->value); + } + if (p->u.func.home_object) { + printf(" HomeObject: "); + JS_DumpValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object)); + } + } + } + printf("\n"); +} + +static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p) +{ + if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { + JS_DumpObject(rt, (JSObject *)p); + } else { + printf("%14p %4d ", + (void *)p, + p->ref_count); + switch(p->gc_obj_type) { + case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: + printf("[function bytecode]"); + break; + case JS_GC_OBJ_TYPE_SHAPE: + printf("[shape]"); + break; + case JS_GC_OBJ_TYPE_VAR_REF: + printf("[var_ref]"); + break; + case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: + printf("[async_function]"); + break; + case JS_GC_OBJ_TYPE_JS_CONTEXT: + printf("[js_context]"); + break; + default: + printf("[unknown %d]", p->gc_obj_type); + break; + } + printf("\n"); + } +} + +static __maybe_unused void JS_DumpValue(JSRuntime *rt, JSValueConst val) +{ + uint32_t tag = JS_VALUE_GET_NORM_TAG(val); + const char *str; + + switch(tag) { + case JS_TAG_INT: + printf("%d", JS_VALUE_GET_INT(val)); + break; + case JS_TAG_BOOL: + if (JS_VALUE_GET_BOOL(val)) + str = "true"; + else + str = "false"; + goto print_str; + case JS_TAG_NULL: + str = "null"; + goto print_str; + case JS_TAG_EXCEPTION: + str = "exception"; + goto print_str; + case JS_TAG_UNINITIALIZED: + str = "uninitialized"; + goto print_str; + case JS_TAG_UNDEFINED: + str = "undefined"; + print_str: + printf("%s", str); + break; + case JS_TAG_FLOAT64: + printf("%.14g", JS_VALUE_GET_FLOAT64(val)); + break; + case JS_TAG_SHORT_BIG_INT: + printf("%" PRId64 "n", (int64_t)JS_VALUE_GET_SHORT_BIG_INT(val)); + break; + case JS_TAG_BIG_INT: + { + JSBigInt *p = JS_VALUE_GET_PTR(val); + int sgn, i; + /* In order to avoid allocations we just dump the limbs */ + sgn = js_bigint_sign(p); + if (sgn) + printf("BigInt.asIntN(%d,", p->len * JS_LIMB_BITS); + printf("0x"); + for(i = p->len - 1; i >= 0; i--) { + if (i != p->len - 1) + printf("_"); + printf("%08x", p->tab[i]); + } + printf("n"); + if (sgn) + printf(")"); + } + break; + case JS_TAG_STRING: + { + JSString *p; + p = JS_VALUE_GET_STRING(val); + JS_DumpString(rt, p); + } + break; + case JS_TAG_FUNCTION_BYTECODE: + { + JSFunctionBytecode *b = JS_VALUE_GET_PTR(val); + char buf[ATOM_GET_STR_BUF_SIZE]; + if (b->func_name) { + printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name)); + } else { + printf("[bytecode (anonymous)]"); + } + } + break; + case JS_TAG_OBJECT: + { + JSObject *p = JS_VALUE_GET_OBJ(val); + JSAtom atom = rt->class_array[p->class_id].class_name; + char atom_buf[ATOM_GET_STR_BUF_SIZE]; + printf("[%s %p]", + JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p); + } + break; + case JS_TAG_SYMBOL: + { + JSAtomStruct *p = JS_VALUE_GET_PTR(val); + char atom_buf[ATOM_GET_STR_BUF_SIZE]; + printf("Symbol(%s)", + JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p))); + } + break; + case JS_TAG_MODULE: + printf("[module]"); + break; + default: + printf("[unknown tag %d]", tag); + break; + } +} + +bool JS_IsArray(JSValueConst val) +{ + if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) { + JSObject *p = JS_VALUE_GET_OBJ(val); + return p->class_id == JS_CLASS_ARRAY; + } + return false; +} + +/* return -1 if exception (proxy case) or true/false */ +static int js_is_array(JSContext *ctx, JSValueConst val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) { + p = JS_VALUE_GET_OBJ(val); + if (unlikely(p->class_id == JS_CLASS_PROXY)) + return js_proxy_isArray(ctx, val); + else + return p->class_id == JS_CLASS_ARRAY; + } else { + return false; + } +} + +static double js_math_pow(double a, double b) +{ + double d; + + if (unlikely(!isfinite(b)) && fabs(a) == 1) { + /* not compatible with IEEE 754 */ + d = NAN; + } else { + JS_X87_FPCW_SAVE_AND_ADJUST(fpcw); + d = pow(a, b); + JS_X87_FPCW_RESTORE(fpcw); + } + return d; +} + +JSValue JS_NewBigInt64(JSContext *ctx, int64_t v) +{ + if (v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX) { + return __JS_NewShortBigInt(ctx, v); + } else { + JSBigInt *p; + p = js_bigint_new_si64(ctx, v); + if (!p) + return JS_EXCEPTION; + return JS_MKPTR(JS_TAG_BIG_INT, p); + } +} + +JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) +{ + if (v <= JS_SHORT_BIG_INT_MAX) { + return __JS_NewShortBigInt(ctx, v); + } else { + JSBigInt *p; + p = js_bigint_new_ui64(ctx, v); + if (!p) + return JS_EXCEPTION; + return JS_MKPTR(JS_TAG_BIG_INT, p); + } +} + +/* return NaN if bad bigint literal */ +static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) +{ + const char *str, *p; + size_t len; + int flags; + + str = JS_ToCStringLen(ctx, &len, val); + JS_FreeValue(ctx, val); + if (!str) + return JS_EXCEPTION; + p = str; + p += skip_spaces(p); + if ((p - str) == len) { + val = JS_NewBigInt64(ctx, 0); + } else { + flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT; + val = js_atof(ctx, p, &p, 0, flags); + p += skip_spaces(p); + if (!JS_IsException(val)) { + if ((p - str) != len) { + JS_FreeValue(ctx, val); + val = JS_NAN; + } + } + } + JS_FreeCString(ctx, str); + return val; +} + +static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val) +{ + val = JS_StringToBigInt(ctx, val); + if (JS_VALUE_IS_NAN(val)) + return JS_ThrowSyntaxError(ctx, "invalid BigInt literal"); + return val; +} + +/* JS Numbers are not allowed */ +static JSValue JS_ToBigIntFree(JSContext *ctx, JSValue val) +{ + uint32_t tag; + + redo: + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_SHORT_BIG_INT: + case JS_TAG_BIG_INT: + break; + case JS_TAG_INT: + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + case JS_TAG_FLOAT64: + goto fail; + case JS_TAG_BOOL: + val = __JS_NewShortBigInt(ctx, JS_VALUE_GET_INT(val)); + break; + case JS_TAG_STRING: + val = JS_StringToBigIntErr(ctx, val); + if (JS_IsException(val)) + return val; + goto redo; + case JS_TAG_OBJECT: + val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); + if (JS_IsException(val)) + return val; + goto redo; + default: + fail: + JS_FreeValue(ctx, val); + return JS_ThrowTypeError(ctx, "cannot convert to bigint"); + } + return val; +} + +static JSValue JS_ToBigInt(JSContext *ctx, JSValueConst val) +{ + return JS_ToBigIntFree(ctx, js_dup(val)); +} + +/* XXX: merge with JS_ToInt64Free with a specific flag */ +static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val) +{ + uint64_t res; + + val = JS_ToBigIntFree(ctx, val); + if (JS_IsException(val)) { + *pres = 0; + return -1; + } + if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) { + res = JS_VALUE_GET_SHORT_BIG_INT(val); + } else { + JSBigInt *p = JS_VALUE_GET_PTR(val); + /* return the value mod 2^64 */ + res = p->tab[0]; + if (p->len >= 2) + res |= (uint64_t)p->tab[1] << 32; + JS_FreeValue(ctx, val); + } + *pres = res; + return 0; +} + +int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val) +{ + return JS_ToBigInt64Free(ctx, pres, js_dup(val)); +} + +int JS_ToBigUint64(JSContext *ctx, uint64_t *pres, JSValueConst val) +{ + return JS_ToBigInt64Free(ctx, (int64_t *)pres, js_dup(val)); +} + +static no_inline __exception int js_unary_arith_slow(JSContext *ctx, + JSValue *sp, + OPCodeEnum op) +{ + JSValue op1; + int v; + uint32_t tag; + JSBigIntBuf buf1; + JSBigInt *p1; + + op1 = sp[-1]; + /* fast path for float64 */ + if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) + goto handle_float64; + op1 = JS_ToNumericFree(ctx, op1); + if (JS_IsException(op1)) + goto exception; + tag = JS_VALUE_GET_TAG(op1); + switch(tag) { + case JS_TAG_INT: + { + int64_t v64; + v64 = JS_VALUE_GET_INT(op1); + switch(op) { + case OP_inc: + case OP_dec: + v = 2 * (op - OP_dec) - 1; + v64 += v; + break; + case OP_plus: + break; + case OP_neg: + if (v64 == 0) { + sp[-1] = js_float64(-0.0); + return 0; + } else { + v64 = -v64; + } + break; + default: + abort(); + } + sp[-1] = js_int64(v64); + } + break; + case JS_TAG_SHORT_BIG_INT: + { + int64_t v; + v = JS_VALUE_GET_SHORT_BIG_INT(op1); + switch(op) { + case OP_plus: + JS_ThrowTypeError(ctx, "bigint argument with unary +"); + goto exception; + case OP_inc: + if (v == JS_SHORT_BIG_INT_MAX) + goto bigint_slow_case; + sp[-1] = __JS_NewShortBigInt(ctx, v + 1); + break; + case OP_dec: + if (v == JS_SHORT_BIG_INT_MIN) + goto bigint_slow_case; + sp[-1] = __JS_NewShortBigInt(ctx, v - 1); + break; + case OP_neg: + v = JS_VALUE_GET_SHORT_BIG_INT(op1); + if (v == JS_SHORT_BIG_INT_MIN) { + bigint_slow_case: + p1 = js_bigint_set_short(&buf1, op1); + goto bigint_slow_case1; + } + sp[-1] = __JS_NewShortBigInt(ctx, -v); + break; + default: + abort(); + } + } + break; + case JS_TAG_BIG_INT: + { + JSBigInt *r; + p1 = JS_VALUE_GET_PTR(op1); + bigint_slow_case1: + switch(op) { + case OP_plus: + JS_ThrowTypeError(ctx, "bigint argument with unary +"); + JS_FreeValue(ctx, op1); + goto exception; + case OP_inc: + case OP_dec: + { + JSBigIntBuf buf2; + JSBigInt *p2; + p2 = js_bigint_set_si(&buf2, 2 * (op - OP_dec) - 1); + r = js_bigint_add(ctx, p1, p2, 0); + } + break; + case OP_neg: + r = js_bigint_neg(ctx, p1); + break; + case OP_not: + r = js_bigint_not(ctx, p1); + break; + default: + abort(); + } + JS_FreeValue(ctx, op1); + if (!r) + goto exception; + sp[-1] = JS_CompactBigInt(ctx, r); + } + break; + default: + handle_float64: + { + double d; + d = JS_VALUE_GET_FLOAT64(op1); + switch(op) { + case OP_inc: + case OP_dec: + v = 2 * (op - OP_dec) - 1; + d += v; + break; + case OP_plus: + break; + case OP_neg: + d = -d; + break; + default: + abort(); + } + sp[-1] = js_float64(d); + } + break; + } + return 0; + exception: + sp[-1] = JS_UNDEFINED; + return -1; +} + +static __exception int js_post_inc_slow(JSContext *ctx, + JSValue *sp, OPCodeEnum op) +{ + JSValue op1; + + /* XXX: allow custom operators */ + op1 = sp[-1]; + op1 = JS_ToNumericFree(ctx, op1); + if (JS_IsException(op1)) { + sp[-1] = JS_UNDEFINED; + return -1; + } + sp[-1] = op1; + sp[0] = js_dup(op1); + return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec); +} + +static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) +{ + JSValue op1; + + op1 = sp[-1]; + op1 = JS_ToNumericFree(ctx, op1); + if (JS_IsException(op1)) + goto exception; + if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) { + sp[-1] = __JS_NewShortBigInt(ctx, ~JS_VALUE_GET_SHORT_BIG_INT(op1)); + } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) { + JSBigInt *r; + r = js_bigint_not(ctx, JS_VALUE_GET_PTR(op1)); + JS_FreeValue(ctx, op1); + if (!r) + goto exception; + sp[-1] = JS_CompactBigInt(ctx, r); + } else { + int32_t v1; + if (unlikely(JS_ToInt32Free(ctx, &v1, op1))) + goto exception; + sp[-1] = js_int32(~v1); + } + return 0; + exception: + sp[-1] = JS_UNDEFINED; + return -1; +} + +static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp, + OPCodeEnum op) +{ + JSValue op1, op2; + uint32_t tag1, tag2; + double d1, d2; + + op1 = sp[-2]; + op2 = sp[-1]; + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + /* fast path for float operations */ + if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) { + d1 = JS_VALUE_GET_FLOAT64(op1); + d2 = JS_VALUE_GET_FLOAT64(op2); + goto handle_float64; + } + /* fast path for short big int operations */ + if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) { + js_slimb_t v1, v2; + js_sdlimb_t v; + v1 = JS_VALUE_GET_SHORT_BIG_INT(op1); + v2 = JS_VALUE_GET_SHORT_BIG_INT(op2); + switch(op) { + case OP_sub: + v = (js_sdlimb_t)v1 - (js_sdlimb_t)v2; + break; + case OP_mul: + v = (js_sdlimb_t)v1 * (js_sdlimb_t)v2; + break; + case OP_div: + if (v2 == 0 || + ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) && + v2 == -1)) { + goto slow_big_int; + } + sp[-2] = __JS_NewShortBigInt(ctx, v1 / v2); + return 0; + case OP_mod: + if (v2 == 0 || + ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) && + v2 == -1)) { + goto slow_big_int; + } + sp[-2] = __JS_NewShortBigInt(ctx, v1 % v2); + return 0; + case OP_pow: + goto slow_big_int; + default: + abort(); + } + if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) { + sp[-2] = __JS_NewShortBigInt(ctx, v); + } else { + JSBigInt *r = js_bigint_new_di(ctx, v); + if (!r) + goto exception; + sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r); + } + return 0; + } + op1 = JS_ToNumericFree(ctx, op1); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + op2 = JS_ToNumericFree(ctx, op2); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + goto exception; + } + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + + if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) { + int32_t v1, v2; + int64_t v; + v1 = JS_VALUE_GET_INT(op1); + v2 = JS_VALUE_GET_INT(op2); + switch(op) { + case OP_sub: + v = (int64_t)v1 - (int64_t)v2; + break; + case OP_mul: + v = (int64_t)v1 * (int64_t)v2; + if (v == 0 && (v1 | v2) < 0) { + sp[-2] = js_float64(-0.0); + return 0; + } + break; + case OP_div: + JS_X87_FPCW_SAVE_AND_ADJUST(fpcw); + sp[-2] = js_number((double)v1 / (double)v2); + JS_X87_FPCW_RESTORE(fpcw); + return 0; + case OP_mod: + if (v1 < 0 || v2 <= 0) { + JS_X87_FPCW_SAVE_AND_ADJUST(fpcw); + sp[-2] = js_number(fmod(v1, v2)); + JS_X87_FPCW_RESTORE(fpcw); + return 0; + } else { + v = (int64_t)v1 % (int64_t)v2; + } + break; + case OP_pow: + sp[-2] = js_number(js_math_pow(v1, v2)); + return 0; + default: + abort(); + } + sp[-2] = js_int64(v); + } else if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_BIG_INT) && + (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_BIG_INT)) { + JSBigInt *p1, *p2, *r; + JSBigIntBuf buf1, buf2; + slow_big_int: + /* bigint result */ + if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) + p1 = js_bigint_set_short(&buf1, op1); + else + p1 = JS_VALUE_GET_PTR(op1); + if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) + p2 = js_bigint_set_short(&buf2, op2); + else + p2 = JS_VALUE_GET_PTR(op2); + switch(op) { + case OP_add: + r = js_bigint_add(ctx, p1, p2, 0); + break; + case OP_sub: + r = js_bigint_add(ctx, p1, p2, 1); + break; + case OP_mul: + r = js_bigint_mul(ctx, p1, p2); + break; + case OP_div: + r = js_bigint_divrem(ctx, p1, p2, false); + break; + case OP_mod: + r = js_bigint_divrem(ctx, p1, p2, true); + break; + case OP_pow: + r = js_bigint_pow(ctx, p1, p2); + break; + default: + abort(); + } + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + if (!r) + goto exception; + sp[-2] = JS_CompactBigInt(ctx, r); + } else { + double dr; + /* float64 result */ + if (JS_ToFloat64Free(ctx, &d1, op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + if (JS_ToFloat64Free(ctx, &d2, op2)) + goto exception; + handle_float64: + JS_X87_FPCW_SAVE_AND_ADJUST(fpcw); + switch(op) { + case OP_sub: + dr = d1 - d2; + break; + case OP_mul: + dr = d1 * d2; + break; + case OP_div: + dr = d1 / d2; + break; + case OP_mod: + dr = fmod(d1, d2); + break; + case OP_pow: + dr = js_math_pow(d1, d2); + break; + default: + abort(); + } + JS_X87_FPCW_RESTORE(fpcw); + sp[-2] = js_float64(dr); + } + return 0; + exception: + sp[-2] = JS_UNDEFINED; + sp[-1] = JS_UNDEFINED; + return -1; +} + +static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) +{ + JSValue op1, op2; + uint32_t tag1, tag2; + + op1 = sp[-2]; + op2 = sp[-1]; + + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + /* fast path for float64 */ + if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) { + double d1, d2; + d1 = JS_VALUE_GET_FLOAT64(op1); + d2 = JS_VALUE_GET_FLOAT64(op2); + sp[-2] = js_float64(d1 + d2); + return 0; + } + /* fast path for short bigint */ + if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) { + js_slimb_t v1, v2; + js_sdlimb_t v; + v1 = JS_VALUE_GET_SHORT_BIG_INT(op1); + v2 = JS_VALUE_GET_SHORT_BIG_INT(op2); + v = (js_sdlimb_t)v1 + (js_sdlimb_t)v2; + if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) { + sp[-2] = __JS_NewShortBigInt(ctx, v); + } else { + JSBigInt *r = js_bigint_new_di(ctx, v); + if (!r) + goto exception; + sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r); + } + return 0; + } + + if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) { + op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + + op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + goto exception; + } + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + } + + if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) { + sp[-2] = JS_ConcatString(ctx, op1, op2); + if (JS_IsException(sp[-2])) + goto exception; + return 0; + } + + op1 = JS_ToNumericFree(ctx, op1); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + op2 = JS_ToNumericFree(ctx, op2); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + goto exception; + } + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + + if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) { + int32_t v1, v2; + int64_t v; + v1 = JS_VALUE_GET_INT(op1); + v2 = JS_VALUE_GET_INT(op2); + v = (int64_t)v1 + (int64_t)v2; + sp[-2] = js_int64(v); + } else if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) && + (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) { + JSBigInt *p1, *p2, *r; + JSBigIntBuf buf1, buf2; + /* bigint result */ + if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) + p1 = js_bigint_set_short(&buf1, op1); + else + p1 = JS_VALUE_GET_PTR(op1); + if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) + p2 = js_bigint_set_short(&buf2, op2); + else + p2 = JS_VALUE_GET_PTR(op2); + r = js_bigint_add(ctx, p1, p2, 0); + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + if (!r) + goto exception; + sp[-2] = JS_CompactBigInt(ctx, r); + } else { + double d1, d2; + /* float64 result */ + if (JS_ToFloat64Free(ctx, &d1, op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + if (JS_ToFloat64Free(ctx, &d2, op2)) + goto exception; + JS_X87_FPCW_SAVE_AND_ADJUST(fpcw); + sp[-2] = js_float64(d1 + d2); + JS_X87_FPCW_RESTORE(fpcw); + } + return 0; + exception: + sp[-2] = JS_UNDEFINED; + sp[-1] = JS_UNDEFINED; + return -1; +} + +static no_inline __exception int js_binary_logic_slow(JSContext *ctx, + JSValue *sp, + OPCodeEnum op) +{ + JSValue op1, op2; + uint32_t tag1, tag2; + uint32_t v1, v2, r; + + op1 = sp[-2]; + op2 = sp[-1]; + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + + if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) { + js_slimb_t v1, v2, v; + js_sdlimb_t vd; + v1 = JS_VALUE_GET_SHORT_BIG_INT(op1); + v2 = JS_VALUE_GET_SHORT_BIG_INT(op2); + /* bigint fast path */ + switch(op) { + case OP_and: + v = v1 & v2; + break; + case OP_or: + v = v1 | v2; + break; + case OP_xor: + v = v1 ^ v2; + break; + case OP_sar: + if (v2 > (JS_LIMB_BITS - 1)) { + goto slow_big_int; + } else if (v2 < 0) { + if (v2 < -(JS_LIMB_BITS - 1)) + goto slow_big_int; + v2 = -v2; + goto bigint_shl; + } + bigint_sar: + v = v1 >> v2; + break; + case OP_shl: + if (v2 > (JS_LIMB_BITS - 1)) { + goto slow_big_int; + } else if (v2 < 0) { + if (v2 < -(JS_LIMB_BITS - 1)) + goto slow_big_int; + v2 = -v2; + goto bigint_sar; + } + bigint_shl: + vd = (js_dlimb_t)v1 << v2; + if (likely(vd >= JS_SHORT_BIG_INT_MIN && + vd <= JS_SHORT_BIG_INT_MAX)) { + v = vd; + } else { + JSBigInt *r = js_bigint_new_di(ctx, vd); + if (!r) + goto exception; + sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r); + return 0; + } + break; + default: + abort(); + } + sp[-2] = __JS_NewShortBigInt(ctx, v); + return 0; + } + op1 = JS_ToNumericFree(ctx, op1); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + op2 = JS_ToNumericFree(ctx, op2); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + goto exception; + } + + tag1 = JS_VALUE_GET_TAG(op1); + tag2 = JS_VALUE_GET_TAG(op2); + if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) && + (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) { + JSBigInt *p1, *p2, *r; + JSBigIntBuf buf1, buf2; + slow_big_int: + if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) + p1 = js_bigint_set_short(&buf1, op1); + else + p1 = JS_VALUE_GET_PTR(op1); + if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) + p2 = js_bigint_set_short(&buf2, op2); + else + p2 = JS_VALUE_GET_PTR(op2); + switch(op) { + case OP_and: + case OP_or: + case OP_xor: + r = js_bigint_logic(ctx, p1, p2, op); + break; + case OP_shl: + case OP_sar: + { + js_slimb_t shift; + shift = js_bigint_get_si_sat(p2); + if (shift > INT32_MAX) + shift = INT32_MAX; + else if (shift < -INT32_MAX) + shift = -INT32_MAX; + if (op == OP_sar) + shift = -shift; + if (shift >= 0) + r = js_bigint_shl(ctx, p1, shift); + else + r = js_bigint_shr(ctx, p1, -shift); + } + break; + default: + abort(); + } + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + if (!r) + goto exception; + sp[-2] = JS_CompactBigInt(ctx, r); + } else { + if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) { + JS_FreeValue(ctx, op2); + goto exception; + } + if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2))) + goto exception; + switch(op) { + case OP_shl: + r = v1 << (v2 & 0x1f); + break; + case OP_sar: + r = (int)v1 >> (v2 & 0x1f); + break; + case OP_and: + r = v1 & v2; + break; + case OP_or: + r = v1 | v2; + break; + case OP_xor: + r = v1 ^ v2; + break; + default: + abort(); + } + sp[-2] = js_int32(r); + } + return 0; + exception: + sp[-2] = JS_UNDEFINED; + sp[-1] = JS_UNDEFINED; + return -1; +} + +/* op1 must be a bigint or int. */ +static JSBigInt *JS_ToBigIntBuf(JSContext *ctx, JSBigIntBuf *buf1, + JSValue op1) +{ + JSBigInt *p1; + + switch(JS_VALUE_GET_TAG(op1)) { + case JS_TAG_INT: + p1 = js_bigint_set_si(buf1, JS_VALUE_GET_INT(op1)); + break; + case JS_TAG_SHORT_BIG_INT: + p1 = js_bigint_set_short(buf1, op1); + break; + case JS_TAG_BIG_INT: + p1 = JS_VALUE_GET_PTR(op1); + break; + default: + abort(); + } + return p1; +} + +/* op1 and op2 must be numeric types and at least one must be a + bigint. No exception is generated. */ +static int js_compare_bigint(JSContext *ctx, OPCodeEnum op, + JSValue op1, JSValue op2) +{ + int res, val, tag1, tag2; + JSBigIntBuf buf1, buf2; + JSBigInt *p1, *p2; + + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_INT) && + (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_INT)) { + /* fast path */ + js_slimb_t v1, v2; + if (tag1 == JS_TAG_INT) + v1 = JS_VALUE_GET_INT(op1); + else + v1 = JS_VALUE_GET_SHORT_BIG_INT(op1); + if (tag2 == JS_TAG_INT) + v2 = JS_VALUE_GET_INT(op2); + else + v2 = JS_VALUE_GET_SHORT_BIG_INT(op2); + val = (v1 > v2) - (v1 < v2); + } else { + if (tag1 == JS_TAG_FLOAT64) { + p2 = JS_ToBigIntBuf(ctx, &buf2, op2); + val = js_bigint_float64_cmp(ctx, p2, JS_VALUE_GET_FLOAT64(op1)); + if (val == 2) + goto unordered; + val = -val; + } else if (tag2 == JS_TAG_FLOAT64) { + p1 = JS_ToBigIntBuf(ctx, &buf1, op1); + val = js_bigint_float64_cmp(ctx, p1, JS_VALUE_GET_FLOAT64(op2)); + if (val == 2) { + unordered: + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + return false; + } + } else { + p1 = JS_ToBigIntBuf(ctx, &buf1, op1); + p2 = JS_ToBigIntBuf(ctx, &buf2, op2); + val = js_bigint_cmp(ctx, p1, p2); + } + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + } + + switch(op) { + case OP_lt: + res = val < 0; + break; + case OP_lte: + res = val <= 0; + break; + case OP_gt: + res = val > 0; + break; + case OP_gte: + res = val >= 0; + break; + case OP_eq: + res = val == 0; + break; + default: + abort(); + } + return res; +} + +static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, + OPCodeEnum op) +{ + JSValue op1, op2; + int res; + uint32_t tag1, tag2; + + op1 = sp[-2]; + op2 = sp[-1]; + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + + op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + goto exception; + } + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + + if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) { + JSString *p1, *p2; + p1 = JS_VALUE_GET_STRING(op1); + p2 = JS_VALUE_GET_STRING(op2); + res = js_string_compare(p1, p2); + switch(op) { + case OP_lt: + res = (res < 0); + break; + case OP_lte: + res = (res <= 0); + break; + case OP_gt: + res = (res > 0); + break; + default: + case OP_gte: + res = (res >= 0); + break; + } + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) && + (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) { + /* fast path for float64/int */ + goto float64_compare; + } else { + if ((((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) && + tag2 == JS_TAG_STRING) || + ((tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) && + tag1 == JS_TAG_STRING))) { + if (tag1 == JS_TAG_STRING) { + op1 = JS_StringToBigInt(ctx, op1); + if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT && + JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT) + goto invalid_bigint_string; + } + if (tag2 == JS_TAG_STRING) { + op2 = JS_StringToBigInt(ctx, op2); + if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT && + JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT) { + invalid_bigint_string: + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + res = false; + goto done; + } + } + } else { + op1 = JS_ToNumericFree(ctx, op1); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + op2 = JS_ToNumericFree(ctx, op2); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + goto exception; + } + } + + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + + if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT || + tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) { + res = js_compare_bigint(ctx, op, op1, op2); + } else { + double d1, d2; + + float64_compare: + /* can use floating point comparison */ + if (tag1 == JS_TAG_FLOAT64) { + d1 = JS_VALUE_GET_FLOAT64(op1); + } else { + d1 = JS_VALUE_GET_INT(op1); + } + if (tag2 == JS_TAG_FLOAT64) { + d2 = JS_VALUE_GET_FLOAT64(op2); + } else { + d2 = JS_VALUE_GET_INT(op2); + } + switch(op) { + case OP_lt: + res = (d1 < d2); /* if NaN return false */ + break; + case OP_lte: + res = (d1 <= d2); /* if NaN return false */ + break; + case OP_gt: + res = (d1 > d2); /* if NaN return false */ + break; + default: + case OP_gte: + res = (d1 >= d2); /* if NaN return false */ + break; + } + } + } + done: + sp[-2] = js_bool(res); + return 0; + exception: + sp[-2] = JS_UNDEFINED; + sp[-1] = JS_UNDEFINED; + return -1; +} + +static bool tag_is_number(uint32_t tag) +{ + return (tag == JS_TAG_INT || + tag == JS_TAG_FLOAT64 || + tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT); +} + +static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, + bool is_neq) +{ + JSValue op1, op2; + int res; + uint32_t tag1, tag2; + + op1 = sp[-2]; + op2 = sp[-1]; + redo: + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + if (tag_is_number(tag1) && tag_is_number(tag2)) { + if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) { + res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2); + } else if ((tag1 == JS_TAG_FLOAT64 && + (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) || + (tag2 == JS_TAG_FLOAT64 && + (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) { + double d1, d2; + if (tag1 == JS_TAG_FLOAT64) { + d1 = JS_VALUE_GET_FLOAT64(op1); + } else { + d1 = JS_VALUE_GET_INT(op1); + } + if (tag2 == JS_TAG_FLOAT64) { + d2 = JS_VALUE_GET_FLOAT64(op2); + } else { + d2 = JS_VALUE_GET_INT(op2); + } + res = (d1 == d2); + } else { + res = js_compare_bigint(ctx, OP_eq, op1, op2); + if (res < 0) + goto exception; + } + } else if (tag1 == tag2) { + res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); + } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) || + (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) { + res = true; + } else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) || + (tag2 == JS_TAG_STRING && tag_is_number(tag1))) { + + if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT || + tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) { + if (tag1 == JS_TAG_STRING) { + op1 = JS_StringToBigInt(ctx, op1); + if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT && + JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT) + goto invalid_bigint_string; + } + if (tag2 == JS_TAG_STRING) { + op2 = JS_StringToBigInt(ctx, op2); + if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT && + JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT ) { + invalid_bigint_string: + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + res = false; + goto done; + } + } + } else { + op1 = JS_ToNumericFree(ctx, op1); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + op2 = JS_ToNumericFree(ctx, op2); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + goto exception; + } + } + res = js_strict_eq(ctx, op1, op2); + } else if (tag1 == JS_TAG_BOOL) { + op1 = js_int32(JS_VALUE_GET_INT(op1)); + goto redo; + } else if (tag2 == JS_TAG_BOOL) { + op2 = js_int32(JS_VALUE_GET_INT(op2)); + goto redo; + } else if ((tag1 == JS_TAG_OBJECT && + (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) || + (tag2 == JS_TAG_OBJECT && + (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) { + op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + goto exception; + } + goto redo; + } else { + /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */ + if ((JS_IsHTMLDDA(ctx, op1) && + (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || + (JS_IsHTMLDDA(ctx, op2) && + (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { + res = true; + } else { + res = false; + } + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + } + done: + sp[-2] = js_bool(res ^ is_neq); + return 0; + exception: + sp[-2] = JS_UNDEFINED; + sp[-1] = JS_UNDEFINED; + return -1; +} + +static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) +{ + JSValue op1, op2; + uint32_t v1, v2, r; + + op1 = sp[-2]; + op2 = sp[-1]; + op1 = JS_ToNumericFree(ctx, op1); + if (JS_IsException(op1)) { + JS_FreeValue(ctx, op2); + goto exception; + } + op2 = JS_ToNumericFree(ctx, op2); + if (JS_IsException(op2)) { + JS_FreeValue(ctx, op1); + goto exception; + } + + if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT || + JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT || + JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT || + JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) { + JS_ThrowTypeError(ctx, "BigInt operands are forbidden for >>>"); + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + goto exception; + } + /* cannot give an exception */ + JS_ToUint32Free(ctx, &v1, op1); + JS_ToUint32Free(ctx, &v2, op2); + r = v1 >> (v2 & 0x1f); + sp[-2] = js_uint32(r); + return 0; + exception: + sp[-2] = JS_UNDEFINED; + sp[-1] = JS_UNDEFINED; + return -1; +} + +static bool js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, + JSStrictEqModeEnum eq_mode) +{ + bool res; + int tag1, tag2; + double d1, d2; + + tag1 = JS_VALUE_GET_NORM_TAG(op1); + tag2 = JS_VALUE_GET_NORM_TAG(op2); + switch(tag1) { + case JS_TAG_BOOL: + if (tag1 != tag2) { + res = false; + } else { + res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2); + goto done_no_free; + } + break; + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + res = (tag1 == tag2); + break; + case JS_TAG_STRING: + { + JSString *p1, *p2; + if (tag1 != tag2) { + res = false; + } else { + p1 = JS_VALUE_GET_STRING(op1); + p2 = JS_VALUE_GET_STRING(op2); + res = js_string_eq(p1, p2); + } + } + break; + case JS_TAG_SYMBOL: + { + JSAtomStruct *p1, *p2; + if (tag1 != tag2) { + res = false; + } else { + p1 = JS_VALUE_GET_PTR(op1); + p2 = JS_VALUE_GET_PTR(op2); + res = (p1 == p2); + } + } + break; + case JS_TAG_OBJECT: + if (tag1 != tag2) + res = false; + else + res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2); + break; + case JS_TAG_INT: + d1 = JS_VALUE_GET_INT(op1); + if (tag2 == JS_TAG_INT) { + d2 = JS_VALUE_GET_INT(op2); + goto number_test; + } else if (tag2 == JS_TAG_FLOAT64) { + d2 = JS_VALUE_GET_FLOAT64(op2); + goto number_test; + } else { + res = false; + } + break; + case JS_TAG_FLOAT64: + d1 = JS_VALUE_GET_FLOAT64(op1); + if (tag2 == JS_TAG_FLOAT64) { + d2 = JS_VALUE_GET_FLOAT64(op2); + } else if (tag2 == JS_TAG_INT) { + d2 = JS_VALUE_GET_INT(op2); + } else { + res = false; + break; + } + number_test: + if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) { + JSFloat64Union u1, u2; + /* NaN is not always normalized, so this test is necessary */ + if (isnan(d1) || isnan(d2)) { + res = isnan(d1) == isnan(d2); + } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) { + res = (d1 == d2); /* +0 == -0 */ + } else { + u1.d = d1; + u2.d = d2; + res = (u1.u64 == u2.u64); /* +0 != -0 */ + } + } else { + res = (d1 == d2); /* if NaN return false and +0 == -0 */ + } + goto done_no_free; + case JS_TAG_SHORT_BIG_INT: + case JS_TAG_BIG_INT: + { + JSBigIntBuf buf1, buf2; + JSBigInt *p1, *p2; + + if (tag2 != JS_TAG_SHORT_BIG_INT && + tag2 != JS_TAG_BIG_INT) { + res = false; + break; + } + + if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) + p1 = js_bigint_set_short(&buf1, op1); + else + p1 = JS_VALUE_GET_PTR(op1); + if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) + p2 = js_bigint_set_short(&buf2, op2); + else + p2 = JS_VALUE_GET_PTR(op2); + res = (js_bigint_cmp(ctx, p1, p2) == 0); + } + break; + default: + res = false; + break; + } + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + done_no_free: + return res; +} + +static bool js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2) +{ + return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); +} + +static bool js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2) +{ + return js_strict_eq2(ctx, js_dup(op1), js_dup(op2), JS_EQ_SAME_VALUE); +} + +static bool js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2) +{ + return js_strict_eq2(ctx, js_dup(op1), js_dup(op2), JS_EQ_SAME_VALUE_ZERO); +} + +static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp, + bool is_neq) +{ + bool res; + res = js_strict_eq(ctx, sp[-2], sp[-1]); + sp[-2] = js_bool(res ^ is_neq); + return 0; +} + +static __exception int js_operator_in(JSContext *ctx, JSValue *sp) +{ + JSValue op1, op2; + JSAtom atom; + int ret; + + op1 = sp[-2]; + op2 = sp[-1]; + + if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) { + JS_ThrowTypeError(ctx, "invalid 'in' operand"); + return -1; + } + atom = JS_ValueToAtom(ctx, op1); + if (unlikely(atom == JS_ATOM_NULL)) + return -1; + ret = JS_HasProperty(ctx, op2, atom); + JS_FreeAtom(ctx, atom); + if (ret < 0) + return -1; + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + sp[-2] = js_bool(ret); + return 0; +} + +static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp) +{ + JSValue op1, op2; + int ret; + op1 = sp[-2]; /* object */ + op2 = sp[-1]; /* field name or method function */ + if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) { + JS_ThrowTypeError(ctx, "invalid 'in' operand"); + return -1; + } + if (JS_IsObject(op2)) { + /* method: use the brand */ + ret = JS_CheckBrand(ctx, op1, op2); + if (ret < 0) + return -1; + } else { + JSAtom atom; + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + /* field */ + atom = JS_ValueToAtom(ctx, op2); + if (unlikely(atom == JS_ATOM_NULL)) + return -1; + p = JS_VALUE_GET_OBJ(op1); + prs = find_own_property(&pr, p, atom); + JS_FreeAtom(ctx, atom); + ret = (prs != NULL); + } + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + sp[-2] = js_bool(ret); + return 0; +} + +static __exception int js_has_unscopable(JSContext *ctx, JSValue obj, + JSAtom atom) +{ + JSValue arr, val; + int ret; + + arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables); + if (JS_IsException(arr)) + return -1; + ret = 0; + if (JS_IsObject(arr)) { + val = JS_GetProperty(ctx, arr, atom); + ret = JS_ToBoolFree(ctx, val); + } + JS_FreeValue(ctx, arr); + return ret; +} + +static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp) +{ + JSValue op1, op2; + int ret; + + op1 = sp[-2]; + op2 = sp[-1]; + ret = JS_IsInstanceOf(ctx, op1, op2); + if (ret < 0) + return ret; + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + sp[-2] = js_bool(ret); + return 0; +} + +static __exception int js_operator_typeof(JSContext *ctx, JSValue op1) +{ + JSAtom atom; + uint32_t tag; + + tag = JS_VALUE_GET_NORM_TAG(op1); + switch(tag) { + case JS_TAG_SHORT_BIG_INT: + case JS_TAG_BIG_INT: + atom = JS_ATOM_bigint; + break; + case JS_TAG_INT: + case JS_TAG_FLOAT64: + atom = JS_ATOM_number; + break; + case JS_TAG_UNDEFINED: + atom = JS_ATOM_undefined; + break; + case JS_TAG_BOOL: + atom = JS_ATOM_boolean; + break; + case JS_TAG_STRING: + atom = JS_ATOM_string; + break; + case JS_TAG_OBJECT: + { + JSObject *p; + p = JS_VALUE_GET_OBJ(op1); + if (unlikely(p->is_HTMLDDA)) + atom = JS_ATOM_undefined; + else if (JS_IsFunction(ctx, op1)) + atom = JS_ATOM_function; + else + goto obj_type; + } + break; + case JS_TAG_NULL: + obj_type: + atom = JS_ATOM_object; + break; + case JS_TAG_SYMBOL: + atom = JS_ATOM_symbol; + break; + default: + atom = JS_ATOM_unknown; + break; + } + return atom; +} + +static __exception int js_operator_delete(JSContext *ctx, JSValue *sp) +{ + JSValue op1, op2; + JSAtom atom; + int ret; + + op1 = sp[-2]; + op2 = sp[-1]; + atom = JS_ValueToAtom(ctx, op2); + if (unlikely(atom == JS_ATOM_NULL)) + return -1; + ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT); + JS_FreeAtom(ctx, atom); + if (unlikely(ret < 0)) + return -1; + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + sp[-2] = js_bool(ret); + return 0; +} + +static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); + if (!b || b->is_strict_mode || !b->has_prototype) { + return JS_ThrowTypeError(ctx, "invalid property access"); + } + return JS_UNDEFINED; +} + +static JSValue js_function_proto_fileName(JSContext *ctx, + JSValueConst this_val) +{ + JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); + if (b) { + return JS_AtomToString(ctx, b->filename); + } + return JS_UNDEFINED; +} + +static JSValue js_function_proto_int32(JSContext *ctx, + JSValueConst this_val, + int magic) +{ + JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); + if (b) { + int *field = (int *) ((char *)b + magic); + return js_int32(*field); + } + return JS_UNDEFINED; +} + +static int js_arguments_define_own_property(JSContext *ctx, + JSValueConst this_obj, + JSAtom prop, JSValueConst val, + JSValueConst getter, + JSValueConst setter, int flags) +{ + JSObject *p; + uint32_t idx; + p = JS_VALUE_GET_OBJ(this_obj); + /* convert to normal array when redefining an existing numeric field */ + if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) && + idx < p->u.array.count) { + if (convert_fast_array_to_array(ctx, p)) + return -1; + } + /* run the default define own property */ + return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter, + flags | JS_PROP_NO_EXOTIC); +} + +static const JSClassExoticMethods js_arguments_exotic_methods = { + .define_own_property = js_arguments_define_own_property, +}; + +static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv) +{ + JSValue val, *tab; + JSProperty *pr; + JSObject *p; + int i; + + val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], + JS_CLASS_ARGUMENTS); + if (JS_IsException(val)) + return val; + p = JS_VALUE_GET_OBJ(val); + + /* add the length field (cannot fail) */ + pr = add_property(ctx, p, JS_ATOM_length, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + if (!pr) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } + pr->u.value = js_int32(argc); + + /* initialize the fast array part */ + tab = NULL; + if (argc > 0) { + tab = js_malloc(ctx, sizeof(tab[0]) * argc); + if (!tab) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } + for(i = 0; i < argc; i++) { + tab[i] = js_dup(argv[i]); + } + } + p->u.array.u.values = tab; + p->u.array.count = argc; + + JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, + js_dup(ctx->array_proto_values), + JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); + /* add callee property to throw a TypeError in strict mode */ + JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED, + ctx->throw_type_error, ctx->throw_type_error, + JS_PROP_HAS_GET | JS_PROP_HAS_SET); + return val; +} + +#define GLOBAL_VAR_OFFSET 0x40000000 +#define ARGUMENT_VAR_OFFSET 0x20000000 + +/* legacy arguments object: add references to the function arguments */ +static JSValue js_build_mapped_arguments(JSContext *ctx, int argc, + JSValueConst *argv, + JSStackFrame *sf, int arg_count) +{ + JSValue val; + JSProperty *pr; + JSObject *p; + int i; + + val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], + JS_CLASS_MAPPED_ARGUMENTS); + if (JS_IsException(val)) + return val; + p = JS_VALUE_GET_OBJ(val); + + /* add the length field (cannot fail) */ + pr = add_property(ctx, p, JS_ATOM_length, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + if (!pr) + goto fail; + pr->u.value = js_int32(argc); + + for(i = 0; i < arg_count; i++) { + JSVarRef *var_ref; + var_ref = get_var_ref(ctx, sf, i, true); + if (!var_ref) + goto fail; + pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF); + if (!pr) { + free_var_ref(ctx->rt, var_ref); + goto fail; + } + pr->u.var_ref = var_ref; + } + + /* the arguments not mapped to the arguments of the function can + be normal properties */ + for(i = arg_count; i < argc; i++) { + if (JS_DefinePropertyValueUint32(ctx, val, i, + js_dup(argv[i]), + JS_PROP_C_W_E) < 0) + goto fail; + } + + JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, + js_dup(ctx->array_proto_values), + JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); + /* callee returns this function in non strict mode */ + JS_DefinePropertyValue(ctx, val, JS_ATOM_callee, + js_dup(ctx->rt->current_stack_frame->cur_func), + JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); + return val; + fail: + JS_FreeValue(ctx, val); + return JS_EXCEPTION; +} + +static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) +{ + JSObject *p; + JSPropertyEnum *tab_atom; + int i; + JSValue enum_obj, obj1; + JSForInIterator *it; + uint32_t tag, tab_atom_count; + + tag = JS_VALUE_GET_TAG(obj); + if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) { + obj = JS_ToObjectFree(ctx, obj); + } + + it = js_malloc(ctx, sizeof(*it)); + if (!it) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR); + if (JS_IsException(enum_obj)) { + js_free(ctx, it); + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + it->is_array = false; + it->obj = obj; + it->idx = 0; + p = JS_VALUE_GET_OBJ(enum_obj); + p->u.for_in_iterator = it; + + if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) + return enum_obj; + + /* fast path: assume no enumerable properties in the prototype chain */ + obj1 = js_dup(obj); + for(;;) { + obj1 = JS_GetPrototypeFree(ctx, obj1); + if (JS_IsNull(obj1)) + break; + if (JS_IsException(obj1)) + goto fail; + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, + JS_VALUE_GET_OBJ(obj1), + JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) { + JS_FreeValue(ctx, obj1); + goto fail; + } + js_free_prop_enum(ctx, tab_atom, tab_atom_count); + if (tab_atom_count != 0) { + JS_FreeValue(ctx, obj1); + goto slow_path; + } + /* must check for timeout to avoid infinite loop */ + if (js_poll_interrupts(ctx)) { + JS_FreeValue(ctx, obj1); + goto fail; + } + } + + p = JS_VALUE_GET_OBJ(obj); + + if (p->fast_array) { + JSShape *sh; + JSShapeProperty *prs; + /* check that there are no enumerable normal fields */ + sh = p->shape; + for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { + if (prs->flags & JS_PROP_ENUMERABLE) + goto normal_case; + } + /* for fast arrays, we only store the number of elements */ + it->is_array = true; + it->array_length = p->u.array.count; + } else { + normal_case: + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, + JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) + goto fail; + for(i = 0; i < tab_atom_count; i++) { + JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0); + } + js_free_prop_enum(ctx, tab_atom, tab_atom_count); + } + return enum_obj; + + slow_path: + /* non enumerable properties hide the enumerables ones in the + prototype chain */ + obj1 = js_dup(obj); + for(;;) { + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, + JS_VALUE_GET_OBJ(obj1), + JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { + JS_FreeValue(ctx, obj1); + goto fail; + } + for(i = 0; i < tab_atom_count; i++) { + JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL, + (tab_atom[i].is_enumerable ? + JS_PROP_ENUMERABLE : 0)); + } + js_free_prop_enum(ctx, tab_atom, tab_atom_count); + obj1 = JS_GetPrototypeFree(ctx, obj1); + if (JS_IsNull(obj1)) + break; + if (JS_IsException(obj1)) + goto fail; + /* must check for timeout to avoid infinite loop */ + if (js_poll_interrupts(ctx)) { + JS_FreeValue(ctx, obj1); + goto fail; + } + } + return enum_obj; + + fail: + JS_FreeValue(ctx, enum_obj); + return JS_EXCEPTION; +} + +/* obj -> enum_obj */ +static __exception int js_for_in_start(JSContext *ctx, JSValue *sp) +{ + sp[-1] = build_for_in_iterator(ctx, sp[-1]); + if (JS_IsException(sp[-1])) + return -1; + return 0; +} + +/* enum_obj -> enum_obj value done */ +static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) +{ + JSValue enum_obj; + JSObject *p; + JSAtom prop; + JSForInIterator *it; + int ret; + + enum_obj = sp[-1]; + /* fail safe */ + if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT) + goto done; + p = JS_VALUE_GET_OBJ(enum_obj); + if (p->class_id != JS_CLASS_FOR_IN_ITERATOR) + goto done; + it = p->u.for_in_iterator; + + for(;;) { + if (it->is_array) { + if (it->idx >= it->array_length) + goto done; + prop = __JS_AtomFromUInt32(it->idx); + it->idx++; + } else { + JSShape *sh = p->shape; + JSShapeProperty *prs; + if (it->idx >= sh->prop_count) + goto done; + prs = get_shape_prop(sh) + it->idx; + prop = prs->atom; + it->idx++; + if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE)) + continue; + } + // check if the property was deleted unless we're dealing with a proxy + JSValue obj = it->obj; + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (p->class_id == JS_CLASS_PROXY) + break; + } + ret = JS_HasProperty(ctx, obj, prop); + if (ret < 0) + return ret; + if (ret) + break; + } + /* return the property */ + sp[0] = JS_AtomToValue(ctx, prop); + sp[1] = JS_FALSE; + return 0; + done: + /* return the end */ + sp[0] = JS_UNDEFINED; + sp[1] = JS_TRUE; + return 0; +} + +static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj, + JSValueConst method) +{ + JSValue enum_obj; + + enum_obj = JS_Call(ctx, method, obj, 0, NULL); + if (JS_IsException(enum_obj)) + return enum_obj; + if (!JS_IsObject(enum_obj)) { + JS_FreeValue(ctx, enum_obj); + return JS_ThrowTypeErrorNotAnObject(ctx); + } + return enum_obj; +} + +static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, bool is_async) +{ + JSValue method, ret, sync_iter; + + if (is_async) { + method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator); + if (JS_IsException(method)) + return method; + if (JS_IsUndefined(method) || JS_IsNull(method)) { + method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator); + if (JS_IsException(method)) + return method; + sync_iter = JS_GetIterator2(ctx, obj, method); + JS_FreeValue(ctx, method); + if (JS_IsException(sync_iter)) + return sync_iter; + ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter); + JS_FreeValue(ctx, sync_iter); + return ret; + } + } else { + method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator); + if (JS_IsException(method)) + return method; + } + if (!JS_IsFunction(ctx, method)) { + JS_FreeValue(ctx, method); + return JS_ThrowTypeError(ctx, "value is not iterable"); + } + ret = JS_GetIterator2(ctx, obj, method); + JS_FreeValue(ctx, method); + return ret; +} + +/* return *pdone = 2 if the iterator object is not parsed */ +static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj, + JSValueConst method, + int argc, JSValueConst *argv, int *pdone) +{ + JSValue obj; + + /* fast path for the built-in iterators (avoid creating the + intermediate result object) */ + if (JS_IsObject(method)) { + JSObject *p = JS_VALUE_GET_OBJ(method); + if (p->class_id == JS_CLASS_C_FUNCTION && + p->u.cfunc.cproto == JS_CFUNC_iterator_next) { + JSCFunctionType func; + JSValueConst args[1]; + + /* in case the function expects one argument */ + if (argc == 0) { + args[0] = JS_UNDEFINED; + argv = args; + } + func = p->u.cfunc.c_function; + return func.iterator_next(ctx, enum_obj, argc, argv, + pdone, p->u.cfunc.magic); + } + } + obj = JS_Call(ctx, method, enum_obj, argc, argv); + if (JS_IsException(obj)) + goto fail; + if (!JS_IsObject(obj)) { + JS_FreeValue(ctx, obj); + JS_ThrowTypeError(ctx, "iterator must return an object"); + goto fail; + } + *pdone = 2; + return obj; + fail: + *pdone = false; + return JS_EXCEPTION; +} + +static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj, + JSValueConst method, + int argc, JSValueConst *argv, int *pdone) +{ + JSValue obj, value, done_val; + int done; + + obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done); + if (JS_IsException(obj)) + goto fail; + if (likely(done == 0)) { + *pdone = false; + return obj; + } else if (done != 2) { + JS_FreeValue(ctx, obj); + *pdone = true; + return JS_UNDEFINED; + } else { + done_val = JS_GetProperty(ctx, obj, JS_ATOM_done); + if (JS_IsException(done_val)) + goto fail; + *pdone = JS_ToBoolFree(ctx, done_val); + value = JS_UNDEFINED; + if (!*pdone) { + value = JS_GetProperty(ctx, obj, JS_ATOM_value); + } + JS_FreeValue(ctx, obj); + return value; + } + fail: + JS_FreeValue(ctx, obj); + *pdone = false; + return JS_EXCEPTION; +} + +/* return < 0 in case of exception */ +static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj, + bool is_exception_pending) +{ + JSValue method, ret, ex_obj; + int res; + + if (is_exception_pending) { + ex_obj = ctx->rt->current_exception; + ctx->rt->current_exception = JS_UNINITIALIZED; + res = -1; + } else { + ex_obj = JS_UNDEFINED; + res = 0; + } + method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return); + if (JS_IsException(method)) { + res = -1; + goto done; + } + if (JS_IsUndefined(method) || JS_IsNull(method)) { + goto done; + } + ret = JS_CallFree(ctx, method, enum_obj, 0, NULL); + if (!is_exception_pending) { + if (JS_IsException(ret)) { + res = -1; + } else if (!JS_IsObject(ret)) { + JS_ThrowTypeErrorNotAnObject(ctx); + res = -1; + } + } + JS_FreeValue(ctx, ret); + done: + if (is_exception_pending) { + JS_Throw(ctx, ex_obj); + } + return res; +} + +/* obj -> enum_rec (3 slots) */ +static __exception int js_for_of_start(JSContext *ctx, JSValue *sp, + bool is_async) +{ + JSValue op1, obj, method; + op1 = sp[-1]; + obj = JS_GetIterator(ctx, op1, is_async); + if (JS_IsException(obj)) + return -1; + JS_FreeValue(ctx, op1); + sp[-1] = obj; + method = JS_GetProperty(ctx, obj, JS_ATOM_next); + if (JS_IsException(method)) + return -1; + sp[0] = method; + return 0; +} + +/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset' + objs. If 'done' is true or in case of exception, 'enum_rec' is set + to undefined. If 'done' is true, 'value' is always set to + undefined. */ +static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset) +{ + JSValue value = JS_UNDEFINED; + int done = 1; + + if (likely(!JS_IsUndefined(sp[offset]))) { + value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done); + if (JS_IsException(value)) + done = -1; + if (done) { + /* value is JS_UNDEFINED or JS_EXCEPTION */ + /* replace the iteration object with undefined */ + JS_FreeValue(ctx, sp[offset]); + sp[offset] = JS_UNDEFINED; + if (done < 0) { + return -1; + } else { + JS_FreeValue(ctx, value); + value = JS_UNDEFINED; + } + } + } + sp[0] = value; + sp[1] = js_bool(done); + return 0; +} + +static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValue obj, + int *pdone) +{ + JSValue done_val, value; + int done; + done_val = JS_GetProperty(ctx, obj, JS_ATOM_done); + if (JS_IsException(done_val)) + goto fail; + done = JS_ToBoolFree(ctx, done_val); + value = JS_GetProperty(ctx, obj, JS_ATOM_value); + if (JS_IsException(value)) + goto fail; + *pdone = done; + return value; + fail: + *pdone = false; + return JS_EXCEPTION; +} + +static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp) +{ + JSValue obj, value; + int done; + obj = sp[-1]; + if (!JS_IsObject(obj)) { + JS_ThrowTypeError(ctx, "iterator must return an object"); + return -1; + } + value = JS_IteratorGetCompleteValue(ctx, obj, &done); + if (JS_IsException(value)) + return -1; + JS_FreeValue(ctx, obj); + sp[-1] = value; + sp[0] = js_bool(done); + return 0; +} + +static JSValue js_create_iterator_result(JSContext *ctx, + JSValue val, + bool done) +{ + JSValue obj; + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) { + JS_FreeValue(ctx, val); + return obj; + } + if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value, + val, JS_PROP_C_W_E) < 0) { + goto fail; + } + if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done, + js_bool(done), JS_PROP_C_W_E) < 0) { + fail: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + return obj; +} + +static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, + int *pdone, int magic); + +static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic); + +static bool js_is_fast_array(JSContext *ctx, JSValue obj) +{ + /* Try and handle fast arrays explicitly */ + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (p->class_id == JS_CLASS_ARRAY && p->fast_array) { + return true; + } + } + return false; +} + +/* Access an Array's internal JSValue array if available */ +static bool js_get_fast_array(JSContext *ctx, JSValue obj, + JSValue **arrpp, uint32_t *countp) +{ + /* Try and handle fast arrays explicitly */ + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (p->class_id == JS_CLASS_ARRAY && p->fast_array) { + *countp = p->u.array.count; + *arrpp = p->u.array.u.values; + return true; + } + } + return false; +} + +static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) +{ + JSValue iterator, enumobj, method, value; + int is_array_iterator; + JSValue *arrp; + uint32_t i, count32, pos; + + if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) { + JS_ThrowInternalError(ctx, "invalid index for append"); + return -1; + } + + pos = JS_VALUE_GET_INT(sp[-2]); + + /* XXX: further optimisations: + - use ctx->array_proto_values? + - check if array_iterator_prototype next method is built-in and + avoid constructing actual iterator object? + - build this into js_for_of_start and use in all `for (x of o)` loops + */ + iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator); + if (JS_IsException(iterator)) + return -1; + /* Used to squelch a -Wcast-function-type warning. */ + JSCFunctionType ft = { .generic_magic = js_create_array_iterator }; + is_array_iterator = JS_IsCFunction(ctx, iterator, + ft.generic, + JS_ITERATOR_KIND_VALUE); + JS_FreeValue(ctx, iterator); + + enumobj = JS_GetIterator(ctx, sp[-1], false); + if (JS_IsException(enumobj)) + return -1; + method = JS_GetProperty(ctx, enumobj, JS_ATOM_next); + if (JS_IsException(method)) { + JS_FreeValue(ctx, enumobj); + return -1; + } + /* Used to squelch a -Wcast-function-type warning. */ + JSCFunctionType ft2 = { .iterator_next = js_array_iterator_next }; + if (is_array_iterator + && JS_IsCFunction(ctx, method, ft2.generic, 0) + && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) { + uint32_t len; + if (js_get_length32(ctx, &len, sp[-1])) + goto exception; + /* if len > count32, the elements >= count32 might be read in + the prototypes and might have side effects */ + if (len != count32) + goto general_case; + /* Handle fast arrays explicitly */ + for (i = 0; i < count32; i++) { + if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, + js_dup(arrp[i]), JS_PROP_C_W_E) < 0) + goto exception; + } + } else { + general_case: + for (;;) { + int done; + value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done); + if (JS_IsException(value)) + goto exception; + if (done) { + /* value is JS_UNDEFINED */ + break; + } + if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0) + goto exception; + } + } + /* Note: could raise an error if too many elements */ + sp[-2] = js_int32(pos); + JS_FreeValue(ctx, enumobj); + JS_FreeValue(ctx, method); + return 0; + +exception: + JS_IteratorClose(ctx, enumobj, true); + JS_FreeValue(ctx, enumobj); + JS_FreeValue(ctx, method); + return -1; +} + +static __exception int JS_CopyDataProperties(JSContext *ctx, + JSValue target, + JSValue source, + JSValue excluded, + bool setprop) +{ + JSPropertyEnum *tab_atom; + JSValue val; + uint32_t i, tab_atom_count; + JSObject *p; + JSObject *pexcl = NULL; + int ret, gpn_flags; + JSPropertyDescriptor desc; + bool is_enumerable; + + if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT) + return 0; + + if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT) + pexcl = JS_VALUE_GET_OBJ(excluded); + + p = JS_VALUE_GET_OBJ(source); + + gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY; + if (p->is_exotic) { + const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; + /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it + introduces a visible change */ + if (em && em->get_own_property_names) { + gpn_flags &= ~JS_GPN_ENUM_ONLY; + } + } + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, + gpn_flags)) + return -1; + + for (i = 0; i < tab_atom_count; i++) { + if (pexcl) { + ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom); + if (ret) { + if (ret < 0) + goto exception; + continue; + } + } + if (!(gpn_flags & JS_GPN_ENUM_ONLY)) { + /* test if the property is enumerable */ + ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom); + if (ret < 0) + goto exception; + if (!ret) + continue; + is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0; + js_free_desc(ctx, &desc); + if (!is_enumerable) + continue; + } + val = JS_GetProperty(ctx, source, tab_atom[i].atom); + if (JS_IsException(val)) + goto exception; + if (setprop) + ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val); + else + ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val, + JS_PROP_C_W_E); + if (ret < 0) + goto exception; + } + js_free_prop_enum(ctx, tab_atom, tab_atom_count); + return 0; + exception: + js_free_prop_enum(ctx, tab_atom, tab_atom_count); + return -1; +} + +/* only valid inside C functions */ +static JSValueConst JS_GetActiveFunction(JSContext *ctx) +{ + return ctx->rt->current_stack_frame->cur_func; +} + +static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, + int var_idx, bool is_arg) +{ + JSVarRef *var_ref; + struct list_head *el; + JSValue *pvalue; + + if (is_arg) + pvalue = &sf->arg_buf[var_idx]; + else + pvalue = &sf->var_buf[var_idx]; + + list_for_each(el, &sf->var_ref_list) { + var_ref = list_entry(el, JSVarRef, header.link); + if (var_ref->pvalue == pvalue) { + var_ref->header.ref_count++; + return var_ref; + } + } + /* create a new one */ + var_ref = js_malloc(ctx, sizeof(JSVarRef)); + if (!var_ref) + return NULL; + var_ref->header.ref_count = 1; + var_ref->is_detached = false; + list_add_tail(&var_ref->header.link, &sf->var_ref_list); + var_ref->pvalue = pvalue; + var_ref->value = JS_UNDEFINED; + return var_ref; +} + +static JSValue js_closure2(JSContext *ctx, JSValue func_obj, + JSFunctionBytecode *b, + JSVarRef **cur_var_refs, + JSStackFrame *sf) +{ + JSObject *p; + JSVarRef **var_refs; + int i; + + p = JS_VALUE_GET_OBJ(func_obj); + p->u.func.function_bytecode = b; + p->u.func.home_object = NULL; + p->u.func.var_refs = NULL; + if (b->closure_var_count) { + var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count); + if (!var_refs) + goto fail; + p->u.func.var_refs = var_refs; + for(i = 0; i < b->closure_var_count; i++) { + JSClosureVar *cv = &b->closure_var[i]; + JSVarRef *var_ref; + if (cv->is_local) { + /* reuse the existing variable reference if it already exists */ + var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg); + if (!var_ref) + goto fail; + } else { + var_ref = cur_var_refs[cv->var_idx]; + var_ref->header.ref_count++; + } + var_refs[i] = var_ref; + } + } + return func_obj; + fail: + /* bfunc is freed when func_obj is freed */ + JS_FreeValue(ctx, func_obj); + return JS_EXCEPTION; +} + +static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque) +{ + JSValue obj, this_val; + int ret; + + this_val = JS_MKPTR(JS_TAG_OBJECT, p); + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) + return JS_EXCEPTION; + ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor, + js_dup(this_val), + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + if (ret < 0) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + return obj; +} + +static const uint16_t func_kind_to_class_id[] = { + [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION, + [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION, + [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION, + [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION, +}; + +static JSValue js_closure(JSContext *ctx, JSValue bfunc, + JSVarRef **cur_var_refs, + JSStackFrame *sf) +{ + JSFunctionBytecode *b; + JSValue func_obj; + JSAtom name_atom; + + b = JS_VALUE_GET_PTR(bfunc); + func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]); + if (JS_IsException(func_obj)) { + JS_FreeValue(ctx, bfunc); + return JS_EXCEPTION; + } + func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf); + if (JS_IsException(func_obj)) { + /* bfunc has been freed */ + goto fail; + } + name_atom = b->func_name; + if (name_atom == JS_ATOM_NULL) + name_atom = JS_ATOM_empty_string; + js_function_set_properties(ctx, func_obj, name_atom, + b->defined_arg_count); + + if (b->func_kind & JS_FUNC_GENERATOR) { + JSValue proto; + int proto_class_id; + /* generators have a prototype field which is used as + prototype for the generator object */ + if (b->func_kind == JS_FUNC_ASYNC_GENERATOR) + proto_class_id = JS_CLASS_ASYNC_GENERATOR; + else + proto_class_id = JS_CLASS_GENERATOR; + proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]); + if (JS_IsException(proto)) + goto fail; + JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto, + JS_PROP_WRITABLE); + } else if (b->has_prototype) { + /* add the 'prototype' property: delay instantiation to avoid + creating cycles for every javascript function. The prototype + object is created on the fly when first accessed */ + JS_SetConstructorBit(ctx, func_obj, true); + JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype, + JS_AUTOINIT_ID_PROTOTYPE, NULL, + JS_PROP_WRITABLE); + } + return func_obj; + fail: + /* bfunc is freed when func_obj is freed */ + JS_FreeValue(ctx, func_obj); + return JS_EXCEPTION; +} + +#define JS_DEFINE_CLASS_HAS_HERITAGE (1 << 0) + +static int js_op_define_class(JSContext *ctx, JSValue *sp, + JSAtom class_name, int class_flags, + JSVarRef **cur_var_refs, + JSStackFrame *sf, bool is_computed_name) +{ + JSValue bfunc, parent_class, proto = JS_UNDEFINED; + JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED; + JSFunctionBytecode *b; + + parent_class = sp[-2]; + bfunc = sp[-1]; + + if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) { + if (JS_IsNull(parent_class)) { + parent_proto = JS_NULL; + parent_class = js_dup(ctx->function_proto); + } else { + if (!JS_IsConstructor(ctx, parent_class)) { + JS_ThrowTypeError(ctx, "parent class must be constructor"); + goto fail; + } + parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype); + if (JS_IsException(parent_proto)) + goto fail; + if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) { + JS_ThrowTypeError(ctx, "parent prototype must be an object or null"); + goto fail; + } + } + } else { + /* parent_class is JS_UNDEFINED in this case */ + parent_proto = js_dup(ctx->class_proto[JS_CLASS_OBJECT]); + parent_class = js_dup(ctx->function_proto); + } + proto = JS_NewObjectProto(ctx, parent_proto); + if (JS_IsException(proto)) + goto fail; + + b = JS_VALUE_GET_PTR(bfunc); + assert(b->func_kind == JS_FUNC_NORMAL); + ctor = JS_NewObjectProtoClass(ctx, parent_class, + JS_CLASS_BYTECODE_FUNCTION); + if (JS_IsException(ctor)) + goto fail; + ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf); + bfunc = JS_UNDEFINED; + if (JS_IsException(ctor)) + goto fail; + js_method_set_home_object(ctx, ctor, proto); + JS_SetConstructorBit(ctx, ctor, true); + + JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length, + js_int32(b->defined_arg_count), + JS_PROP_CONFIGURABLE); + + if (is_computed_name) { + if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3], + JS_PROP_CONFIGURABLE) < 0) + goto fail; + } else { + if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0) + goto fail; + } + + /* the constructor property must be first. It can be overriden by + computed property names */ + if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, + js_dup(ctor), + JS_PROP_CONFIGURABLE | + JS_PROP_WRITABLE | JS_PROP_THROW) < 0) + goto fail; + /* set the prototype property */ + if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype, + js_dup(proto), JS_PROP_THROW) < 0) + goto fail; + + JS_FreeValue(ctx, parent_proto); + JS_FreeValue(ctx, parent_class); + + sp[-2] = ctor; + sp[-1] = proto; + return 0; + fail: + JS_FreeValue(ctx, parent_class); + JS_FreeValue(ctx, parent_proto); + JS_FreeValue(ctx, bfunc); + JS_FreeValue(ctx, proto); + JS_FreeValue(ctx, ctor); + sp[-2] = JS_UNDEFINED; + sp[-1] = JS_UNDEFINED; + return -1; +} + +static void close_var_refs(JSRuntime *rt, JSStackFrame *sf) +{ + struct list_head *el, *el1; + JSVarRef *var_ref; + + list_for_each_safe(el, el1, &sf->var_ref_list) { + var_ref = list_entry(el, JSVarRef, header.link); + var_ref->value = js_dup(*var_ref->pvalue); + var_ref->pvalue = &var_ref->value; + /* the reference is no longer to a local variable */ + var_ref->is_detached = true; + add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); + } +} + +static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int var_idx) +{ + JSValue *pvalue; + struct list_head *el, *el1; + JSVarRef *var_ref; + + pvalue = &sf->var_buf[var_idx]; + list_for_each_safe(el, el1, &sf->var_ref_list) { + var_ref = list_entry(el, JSVarRef, header.link); + if (var_ref->pvalue == pvalue) { + var_ref->value = js_dup(*var_ref->pvalue); + var_ref->pvalue = &var_ref->value; + list_del(&var_ref->header.link); + /* the reference is no longer to a local variable */ + var_ref->is_detached = true; + add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); + } + } +} + +#define JS_CALL_FLAG_COPY_ARGV (1 << 1) +#define JS_CALL_FLAG_GENERATOR (1 << 2) + +static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv, int flags) +{ + JSRuntime *rt = ctx->rt; + JSCFunctionType func; + JSObject *p; + JSStackFrame sf_s, *sf = &sf_s, *prev_sf; + JSValue ret_val; + JSValueConst *arg_buf; + int arg_count, i; + JSCFunctionEnum cproto; + + p = JS_VALUE_GET_OBJ(func_obj); + cproto = p->u.cfunc.cproto; + arg_count = p->u.cfunc.length; + + /* better to always check stack overflow */ + if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count)) + return JS_ThrowStackOverflow(ctx); + + prev_sf = rt->current_stack_frame; + sf->prev_frame = prev_sf; + rt->current_stack_frame = sf; + ctx = p->u.cfunc.realm; /* change the current realm */ + + sf->is_strict_mode = false; + sf->cur_func = unsafe_unconst(func_obj); + sf->arg_count = argc; + arg_buf = argv; + + if (unlikely(argc < arg_count)) { + /* ensure that at least argc_count arguments are readable */ + arg_buf = alloca(sizeof(arg_buf[0]) * arg_count); + for(i = 0; i < argc; i++) + arg_buf[i] = argv[i]; + for(i = argc; i < arg_count; i++) + arg_buf[i] = JS_UNDEFINED; + sf->arg_count = arg_count; + } + sf->arg_buf = (JSValue *)arg_buf; + + func = p->u.cfunc.c_function; + switch(cproto) { + case JS_CFUNC_constructor: + case JS_CFUNC_constructor_or_func: + if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) { + if (cproto == JS_CFUNC_constructor) { + not_a_constructor: + ret_val = JS_ThrowTypeError(ctx, "must be called with new"); + break; + } else { + this_obj = JS_UNDEFINED; + } + } + /* here this_obj is new_target */ + /* fall thru */ + case JS_CFUNC_generic: + ret_val = func.generic(ctx, this_obj, argc, arg_buf); + break; + case JS_CFUNC_constructor_magic: + case JS_CFUNC_constructor_or_func_magic: + if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) { + if (cproto == JS_CFUNC_constructor_magic) { + goto not_a_constructor; + } else { + this_obj = JS_UNDEFINED; + } + } + /* fall thru */ + case JS_CFUNC_generic_magic: + ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf, + p->u.cfunc.magic); + break; + case JS_CFUNC_getter: + ret_val = func.getter(ctx, this_obj); + break; + case JS_CFUNC_setter: + ret_val = func.setter(ctx, this_obj, arg_buf[0]); + break; + case JS_CFUNC_getter_magic: + ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic); + break; + case JS_CFUNC_setter_magic: + ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic); + break; + case JS_CFUNC_f_f: + { + double d1; + + if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) { + ret_val = JS_EXCEPTION; + break; + } + ret_val = js_number(func.f_f(d1)); + } + break; + case JS_CFUNC_f_f_f: + { + double d1, d2; + + if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) { + ret_val = JS_EXCEPTION; + break; + } + if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) { + ret_val = JS_EXCEPTION; + break; + } + ret_val = js_number(func.f_f_f(d1, d2)); + } + break; + case JS_CFUNC_iterator_next: + { + int done; + ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf, + &done, p->u.cfunc.magic); + if (!JS_IsException(ret_val) && done != 2) { + ret_val = js_create_iterator_result(ctx, ret_val, done); + } + } + break; + default: + abort(); + } + + rt->current_stack_frame = sf->prev_frame; + return ret_val; +} + +static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv, int flags) +{ + JSObject *p; + JSBoundFunction *bf; + JSValueConst *arg_buf, new_target; + int arg_count, i; + + p = JS_VALUE_GET_OBJ(func_obj); + bf = p->u.bound_function; + arg_count = bf->argc + argc; + if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count)) + return JS_ThrowStackOverflow(ctx); + arg_buf = alloca(sizeof(JSValue) * arg_count); + for(i = 0; i < bf->argc; i++) { + arg_buf[i] = bf->argv[i]; + } + for(i = 0; i < argc; i++) { + arg_buf[bf->argc + i] = argv[i]; + } + if (flags & JS_CALL_FLAG_CONSTRUCTOR) { + new_target = this_obj; + if (js_same_value(ctx, func_obj, new_target)) + new_target = bf->func_obj; + return JS_CallConstructor2(ctx, bf->func_obj, new_target, + arg_count, arg_buf); + } else { + return JS_Call(ctx, bf->func_obj, bf->this_val, + arg_count, arg_buf); + } +} + +/* argument of OP_special_object */ +typedef enum { + OP_SPECIAL_OBJECT_ARGUMENTS, + OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS, + OP_SPECIAL_OBJECT_THIS_FUNC, + OP_SPECIAL_OBJECT_NEW_TARGET, + OP_SPECIAL_OBJECT_HOME_OBJECT, + OP_SPECIAL_OBJECT_VAR_OBJECT, + OP_SPECIAL_OBJECT_IMPORT_META, + OP_SPECIAL_OBJECT_NULL_PROTO, +} OPSpecialObjectEnum; + +#define FUNC_RET_AWAIT 0 +#define FUNC_RET_YIELD 1 +#define FUNC_RET_YIELD_STAR 2 + +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_* +static void dump_single_byte_code(JSContext *ctx, const uint8_t *pc, + JSFunctionBytecode *b, int start_pos); +static void print_func_name(JSFunctionBytecode *b); +#endif + +static bool needs_backtrace(JSValue exc) +{ + JSObject *p; + + if (JS_VALUE_GET_TAG(exc) != JS_TAG_OBJECT) + return false; + p = JS_VALUE_GET_OBJ(exc); + if (p->class_id != JS_CLASS_ERROR) + return false; + return !find_own_property1(p, JS_ATOM_stack); +} + +/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ +static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, + JSValueConst this_obj, JSValueConst new_target, + int argc, JSValueConst *argv, int flags) +{ + JSRuntime *rt = caller_ctx->rt; + JSContext *ctx; + JSObject *p; + JSFunctionBytecode *b; + JSStackFrame sf_s, *sf = &sf_s; + uint8_t *pc; + int opcode, arg_allocated_size, i; + JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval; + JSVarRef **var_refs; + size_t alloca_size; + +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_STEP +#define DUMP_BYTECODE_OR_DONT(pc) \ + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_STEP)) dump_single_byte_code(ctx, pc, b, 0); +#else +#define DUMP_BYTECODE_OR_DONT(pc) +#endif + +#if !DIRECT_DISPATCH +#define SWITCH(pc) DUMP_BYTECODE_OR_DONT(pc) switch (opcode = *pc++) +#define CASE(op) case op +#define DEFAULT default +#define BREAK break +#else + __extension__ static const void * const dispatch_table[256] = { +#define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id, +#define def(id, size, n_pop, n_push, f) +#include "quickjs-opcode.h" + [ OP_COUNT ... 255 ] = &&case_default + }; +#define SWITCH(pc) DUMP_BYTECODE_OR_DONT(pc) __extension__ ({ goto *dispatch_table[opcode = *pc++]; }); +#define CASE(op) case_ ## op +#define DEFAULT case_default +#define BREAK SWITCH(pc) +#endif + + if (js_poll_interrupts(caller_ctx)) + return JS_EXCEPTION; + if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) { + if (flags & JS_CALL_FLAG_GENERATOR) { + JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj); + /* func_obj get contains a pointer to JSFuncAsyncState */ + /* the stack frame is already allocated */ + sf = &s->frame; + p = JS_VALUE_GET_OBJ(sf->cur_func); + b = p->u.func.function_bytecode; + ctx = b->realm; + var_refs = p->u.func.var_refs; + local_buf = arg_buf = sf->arg_buf; + var_buf = sf->var_buf; + stack_buf = sf->var_buf + b->var_count; + sp = sf->cur_sp; + sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */ + pc = sf->cur_pc; + sf->prev_frame = rt->current_stack_frame; + rt->current_stack_frame = sf; + if (s->throw_flag) + goto exception; + else + goto restart; + } else { + goto not_a_function; + } + } + p = JS_VALUE_GET_OBJ(func_obj); + if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) { + JSClassCall *call_func; + call_func = rt->class_array[p->class_id].call; + if (!call_func) { + not_a_function: + return JS_ThrowTypeErrorNotAFunction(caller_ctx); + } + return call_func(caller_ctx, func_obj, this_obj, argc, + argv, flags); + } + b = p->u.func.function_bytecode; + + if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) { + arg_allocated_size = b->arg_count; + } else { + arg_allocated_size = 0; + } + + alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count + + b->stack_size); + if (js_check_stack_overflow(rt, alloca_size)) + return JS_ThrowStackOverflow(caller_ctx); + + sf->is_strict_mode = b->is_strict_mode; + arg_buf = (JSValue *)argv; + sf->arg_count = argc; + sf->cur_func = unsafe_unconst(func_obj); + init_list_head(&sf->var_ref_list); + var_refs = p->u.func.var_refs; + + local_buf = alloca(alloca_size); + if (unlikely(arg_allocated_size)) { + int n = min_int(argc, b->arg_count); + arg_buf = local_buf; + for(i = 0; i < n; i++) + arg_buf[i] = js_dup(argv[i]); + for(; i < b->arg_count; i++) + arg_buf[i] = JS_UNDEFINED; + sf->arg_count = b->arg_count; + } + var_buf = local_buf + arg_allocated_size; + sf->var_buf = var_buf; + sf->arg_buf = arg_buf; + + for(i = 0; i < b->var_count; i++) + var_buf[i] = JS_UNDEFINED; + + stack_buf = var_buf + b->var_count; + sp = stack_buf; + pc = b->byte_code_buf; + /* sf->cur_pc must we set to pc before any recursive calls to JS_CallInternal. */ + sf->cur_pc = NULL; + sf->prev_frame = rt->current_stack_frame; + rt->current_stack_frame = sf; + ctx = b->realm; /* set the current realm */ + +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_STEP + if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_STEP)) + print_func_name(b); +#endif + + restart: + for(;;) { + int call_argc; + JSValue *call_argv; + + SWITCH(pc) { + CASE(OP_push_i32): + *sp++ = js_int32(get_u32(pc)); + pc += 4; + BREAK; + CASE(OP_push_bigint_i32): + *sp++ = __JS_NewShortBigInt(ctx, (int)get_u32(pc)); + pc += 4; + BREAK; + CASE(OP_push_const): + *sp++ = js_dup(b->cpool[get_u32(pc)]); + pc += 4; + BREAK; + CASE(OP_push_minus1): + CASE(OP_push_0): + CASE(OP_push_1): + CASE(OP_push_2): + CASE(OP_push_3): + CASE(OP_push_4): + CASE(OP_push_5): + CASE(OP_push_6): + CASE(OP_push_7): + *sp++ = js_int32(opcode - OP_push_0); + BREAK; + CASE(OP_push_i8): + *sp++ = js_int32(get_i8(pc)); + pc += 1; + BREAK; + CASE(OP_push_i16): + *sp++ = js_int32(get_i16(pc)); + pc += 2; + BREAK; + CASE(OP_push_const8): + *sp++ = js_dup(b->cpool[*pc++]); + BREAK; + CASE(OP_fclosure8): + *sp++ = js_closure(ctx, js_dup(b->cpool[*pc++]), var_refs, sf); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + BREAK; + CASE(OP_push_empty_string): + *sp++ = js_empty_string(rt); + BREAK; + CASE(OP_get_length): + { + JSValue val; + + sf->cur_pc = pc; + val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length); + if (unlikely(JS_IsException(val))) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = val; + } + BREAK; + CASE(OP_push_atom_value): + *sp++ = JS_AtomToValue(ctx, get_u32(pc)); + pc += 4; + BREAK; + CASE(OP_undefined): + *sp++ = JS_UNDEFINED; + BREAK; + CASE(OP_null): + *sp++ = JS_NULL; + BREAK; + CASE(OP_push_this): + /* OP_push_this is only called at the start of a function */ + { + JSValue val; + if (!b->is_strict_mode) { + uint32_t tag = JS_VALUE_GET_TAG(this_obj); + if (likely(tag == JS_TAG_OBJECT)) + goto normal_this; + if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) { + val = js_dup(ctx->global_obj); + } else { + val = JS_ToObject(ctx, this_obj); + if (JS_IsException(val)) + goto exception; + } + } else { + normal_this: + val = js_dup(this_obj); + } + *sp++ = val; + } + BREAK; + CASE(OP_push_false): + *sp++ = JS_FALSE; + BREAK; + CASE(OP_push_true): + *sp++ = JS_TRUE; + BREAK; + CASE(OP_object): + *sp++ = JS_NewObject(ctx); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + BREAK; + CASE(OP_special_object): + { + int arg = *pc++; + switch(arg) { + case OP_SPECIAL_OBJECT_ARGUMENTS: + *sp++ = js_build_arguments(ctx, argc, argv); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + break; + case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS: + *sp++ = js_build_mapped_arguments(ctx, argc, argv, + sf, min_int(argc, b->arg_count)); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + break; + case OP_SPECIAL_OBJECT_THIS_FUNC: + *sp++ = js_dup(sf->cur_func); + break; + case OP_SPECIAL_OBJECT_NEW_TARGET: + *sp++ = js_dup(new_target); + break; + case OP_SPECIAL_OBJECT_HOME_OBJECT: + { + JSObject *p1; + p1 = p->u.func.home_object; + if (unlikely(!p1)) + *sp++ = JS_UNDEFINED; + else + *sp++ = js_dup(JS_MKPTR(JS_TAG_OBJECT, p1)); + } + break; + case OP_SPECIAL_OBJECT_VAR_OBJECT: + *sp++ = JS_NewObjectProto(ctx, JS_NULL); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + break; + case OP_SPECIAL_OBJECT_IMPORT_META: + *sp++ = js_import_meta(ctx); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + break; + case OP_SPECIAL_OBJECT_NULL_PROTO: + *sp++ = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OBJECT); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + break; + default: + abort(); + } + } + BREAK; + CASE(OP_rest): + { + int i, n, first = get_u16(pc); + pc += 2; + i = min_int(first, argc); + n = argc - i; + *sp++ = js_create_array(ctx, n, &argv[i]); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + } + BREAK; + + CASE(OP_drop): + JS_FreeValue(ctx, sp[-1]); + sp--; + BREAK; + CASE(OP_nip): + JS_FreeValue(ctx, sp[-2]); + sp[-2] = sp[-1]; + sp--; + BREAK; + CASE(OP_nip1): /* a b c -> b c */ + JS_FreeValue(ctx, sp[-3]); + sp[-3] = sp[-2]; + sp[-2] = sp[-1]; + sp--; + BREAK; + CASE(OP_dup): + sp[0] = js_dup(sp[-1]); + sp++; + BREAK; + CASE(OP_dup2): /* a b -> a b a b */ + sp[0] = js_dup(sp[-2]); + sp[1] = js_dup(sp[-1]); + sp += 2; + BREAK; + CASE(OP_dup3): /* a b c -> a b c a b c */ + sp[0] = js_dup(sp[-3]); + sp[1] = js_dup(sp[-2]); + sp[2] = js_dup(sp[-1]); + sp += 3; + BREAK; + CASE(OP_dup1): /* a b -> a a b */ + sp[0] = sp[-1]; + sp[-1] = js_dup(sp[-2]); + sp++; + BREAK; + CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */ + sp[0] = sp[-1]; + sp[-1] = sp[-2]; + sp[-2] = js_dup(sp[0]); + sp++; + BREAK; + CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */ + sp[0] = sp[-1]; + sp[-1] = sp[-2]; + sp[-2] = sp[-3]; + sp[-3] = js_dup(sp[0]); + sp++; + BREAK; + CASE(OP_insert4): /* this obj prop a -> a this obj prop a */ + sp[0] = sp[-1]; + sp[-1] = sp[-2]; + sp[-2] = sp[-3]; + sp[-3] = sp[-4]; + sp[-4] = js_dup(sp[0]); + sp++; + BREAK; + CASE(OP_perm3): /* obj a b -> a obj b (213) */ + { + JSValue tmp; + tmp = sp[-2]; + sp[-2] = sp[-3]; + sp[-3] = tmp; + } + BREAK; + CASE(OP_rot3l): /* x a b -> a b x (231) */ + { + JSValue tmp; + tmp = sp[-3]; + sp[-3] = sp[-2]; + sp[-2] = sp[-1]; + sp[-1] = tmp; + } + BREAK; + CASE(OP_rot4l): /* x a b c -> a b c x */ + { + JSValue tmp; + tmp = sp[-4]; + sp[-4] = sp[-3]; + sp[-3] = sp[-2]; + sp[-2] = sp[-1]; + sp[-1] = tmp; + } + BREAK; + CASE(OP_rot5l): /* x a b c d -> a b c d x */ + { + JSValue tmp; + tmp = sp[-5]; + sp[-5] = sp[-4]; + sp[-4] = sp[-3]; + sp[-3] = sp[-2]; + sp[-2] = sp[-1]; + sp[-1] = tmp; + } + BREAK; + CASE(OP_rot3r): /* a b x -> x a b (312) */ + { + JSValue tmp; + tmp = sp[-1]; + sp[-1] = sp[-2]; + sp[-2] = sp[-3]; + sp[-3] = tmp; + } + BREAK; + CASE(OP_perm4): /* obj prop a b -> a obj prop b */ + { + JSValue tmp; + tmp = sp[-2]; + sp[-2] = sp[-3]; + sp[-3] = sp[-4]; + sp[-4] = tmp; + } + BREAK; + CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */ + { + JSValue tmp; + tmp = sp[-2]; + sp[-2] = sp[-3]; + sp[-3] = sp[-4]; + sp[-4] = sp[-5]; + sp[-5] = tmp; + } + BREAK; + CASE(OP_swap): /* a b -> b a */ + { + JSValue tmp; + tmp = sp[-2]; + sp[-2] = sp[-1]; + sp[-1] = tmp; + } + BREAK; + CASE(OP_swap2): /* a b c d -> c d a b */ + { + JSValue tmp1, tmp2; + tmp1 = sp[-4]; + tmp2 = sp[-3]; + sp[-4] = sp[-2]; + sp[-3] = sp[-1]; + sp[-2] = tmp1; + sp[-1] = tmp2; + } + BREAK; + + CASE(OP_fclosure): + { + JSValue bfunc = js_dup(b->cpool[get_u32(pc)]); + pc += 4; + *sp++ = js_closure(ctx, bfunc, var_refs, sf); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + } + BREAK; + CASE(OP_call0): + CASE(OP_call1): + CASE(OP_call2): + CASE(OP_call3): + call_argc = opcode - OP_call0; + goto has_call_argc; + CASE(OP_call): + CASE(OP_tail_call): + { + call_argc = get_u16(pc); + pc += 2; + goto has_call_argc; + has_call_argc: + call_argv = sp - call_argc; + sf->cur_pc = pc; + ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED, + JS_UNDEFINED, call_argc, + vc(call_argv), 0); + if (unlikely(JS_IsException(ret_val))) + goto exception; + if (opcode == OP_tail_call) + goto done; + for(i = -1; i < call_argc; i++) + JS_FreeValue(ctx, call_argv[i]); + sp -= call_argc + 1; + *sp++ = ret_val; + } + BREAK; + CASE(OP_call_constructor): + { + call_argc = get_u16(pc); + pc += 2; + call_argv = sp - call_argc; + sf->cur_pc = pc; + ret_val = JS_CallConstructorInternal(ctx, call_argv[-2], + call_argv[-1], call_argc, + vc(call_argv), 0); + if (unlikely(JS_IsException(ret_val))) + goto exception; + for(i = -2; i < call_argc; i++) + JS_FreeValue(ctx, call_argv[i]); + sp -= call_argc + 2; + *sp++ = ret_val; + } + BREAK; + CASE(OP_call_method): + CASE(OP_tail_call_method): + { + call_argc = get_u16(pc); + pc += 2; + call_argv = sp - call_argc; + sf->cur_pc = pc; + ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2], + JS_UNDEFINED, call_argc, + vc(call_argv), 0); + if (unlikely(JS_IsException(ret_val))) + goto exception; + if (opcode == OP_tail_call_method) + goto done; + for(i = -2; i < call_argc; i++) + JS_FreeValue(ctx, call_argv[i]); + sp -= call_argc + 2; + *sp++ = ret_val; + } + BREAK; + CASE(OP_array_from): + { + call_argc = get_u16(pc); + pc += 2; + call_argv = sp - call_argc; + ret_val = JS_NewArrayFrom(ctx, call_argc, call_argv); + sp -= call_argc; + if (unlikely(JS_IsException(ret_val))) + goto exception; + *sp++ = ret_val; + } + BREAK; + + CASE(OP_apply): + { + int magic; + magic = get_u16(pc); + pc += 2; + sf->cur_pc = pc; + + ret_val = js_function_apply(ctx, sp[-3], 2, vc(&sp[-2]), magic); + if (unlikely(JS_IsException(ret_val))) + goto exception; + JS_FreeValue(ctx, sp[-3]); + JS_FreeValue(ctx, sp[-2]); + JS_FreeValue(ctx, sp[-1]); + sp -= 3; + *sp++ = ret_val; + } + BREAK; + CASE(OP_return): + ret_val = *--sp; + goto done; + CASE(OP_return_undef): + ret_val = JS_UNDEFINED; + goto done; + + CASE(OP_check_ctor_return): + /* return true if 'this' should be returned */ + if (!JS_IsObject(sp[-1])) { + if (!JS_IsUndefined(sp[-1])) { + JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined"); + goto exception; + } + sp[0] = JS_TRUE; + } else { + sp[0] = JS_FALSE; + } + sp++; + BREAK; + CASE(OP_check_ctor): + if (JS_IsUndefined(new_target)) { + non_ctor_call: + JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'"); + goto exception; + } + BREAK; + CASE(OP_init_ctor): + { + JSValue super, ret; + sf->cur_pc = pc; + if (JS_IsUndefined(new_target)) + goto non_ctor_call; + super = JS_GetPrototype(ctx, func_obj); + if (JS_IsException(super)) + goto exception; + ret = JS_CallConstructor2(ctx, super, new_target, argc, argv); + JS_FreeValue(ctx, super); + if (JS_IsException(ret)) + goto exception; + *sp++ = ret; + } + BREAK; + CASE(OP_check_brand): + { + int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]); + if (ret < 0) + goto exception; + if (!ret) { + JS_ThrowTypeError(ctx, "invalid brand on object"); + goto exception; + } + } + BREAK; + CASE(OP_add_brand): + if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0) + goto exception; + JS_FreeValue(ctx, sp[-2]); + JS_FreeValue(ctx, sp[-1]); + sp -= 2; + BREAK; + + CASE(OP_throw): + JS_Throw(ctx, *--sp); + goto exception; + + CASE(OP_throw_error): +#define JS_THROW_VAR_RO 0 +#define JS_THROW_VAR_REDECL 1 +#define JS_THROW_VAR_UNINITIALIZED 2 +#define JS_THROW_ERROR_DELETE_SUPER 3 +#define JS_THROW_ERROR_ITERATOR_THROW 4 + { + JSAtom atom; + int type; + atom = get_u32(pc); + type = pc[4]; + pc += 5; + if (type == JS_THROW_VAR_RO) + JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom); + else + if (type == JS_THROW_VAR_REDECL) + JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom); + else + if (type == JS_THROW_VAR_UNINITIALIZED) + JS_ThrowReferenceErrorUninitialized(ctx, atom); + else + if (type == JS_THROW_ERROR_DELETE_SUPER) + JS_ThrowReferenceError(ctx, "unsupported reference to 'super'"); + else + if (type == JS_THROW_ERROR_ITERATOR_THROW) + JS_ThrowTypeError(ctx, "iterator does not have a throw method"); + else + JS_ThrowInternalError(ctx, "invalid throw var type %d", type); + } + goto exception; + + CASE(OP_eval): + { + JSValue obj; + int scope_idx; + call_argc = get_u16(pc); + scope_idx = get_u16(pc + 2) - 1; + pc += 4; + call_argv = sp - call_argc; + sf->cur_pc = pc; + if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) { + if (call_argc >= 1) + obj = call_argv[0]; + else + obj = JS_UNDEFINED; + ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj, + JS_EVAL_TYPE_DIRECT, scope_idx); + } else { + ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED, + JS_UNDEFINED, call_argc, + vc(call_argv), 0); + } + if (unlikely(JS_IsException(ret_val))) + goto exception; + for(i = -1; i < call_argc; i++) + JS_FreeValue(ctx, call_argv[i]); + sp -= call_argc + 1; + *sp++ = ret_val; + } + BREAK; + /* could merge with OP_apply */ + CASE(OP_apply_eval): + { + int scope_idx; + uint32_t len; + JSValue *tab; + JSValue obj; + + scope_idx = get_u16(pc) - 1; + pc += 2; + sf->cur_pc = pc; + tab = build_arg_list(ctx, &len, sp[-1]); + if (!tab) + goto exception; + if (js_same_value(ctx, sp[-2], ctx->eval_obj)) { + if (len >= 1) + obj = tab[0]; + else + obj = JS_UNDEFINED; + ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj, + JS_EVAL_TYPE_DIRECT, scope_idx); + } else { + ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len, vc(tab)); + } + free_arg_list(ctx, tab, len); + if (unlikely(JS_IsException(ret_val))) + goto exception; + JS_FreeValue(ctx, sp[-2]); + JS_FreeValue(ctx, sp[-1]); + sp -= 2; + *sp++ = ret_val; + } + BREAK; + + CASE(OP_regexp): + { + sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED, + sp[-2], sp[-1]); + sp--; + } + BREAK; + + CASE(OP_get_super): + { + JSValue proto; + proto = JS_GetPrototype(ctx, sp[-1]); + if (JS_IsException(proto)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = proto; + } + BREAK; + + CASE(OP_import): + { + JSValue val; + sf->cur_pc = pc; + val = js_dynamic_import(ctx, sp[-1]); + if (JS_IsException(val)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = val; + } + BREAK; + + CASE(OP_check_var): + { + int ret; + JSAtom atom; + atom = get_u32(pc); + pc += 4; + + ret = JS_CheckGlobalVar(ctx, atom); + if (ret < 0) + goto exception; + *sp++ = js_bool(ret); + } + BREAK; + + CASE(OP_get_var_undef): + CASE(OP_get_var): + { + JSValue val; + JSAtom atom; + atom = get_u32(pc); + pc += 4; + sf->cur_pc = pc; + + val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef); + if (unlikely(JS_IsException(val))) + goto exception; + *sp++ = val; + } + BREAK; + + CASE(OP_put_var): + CASE(OP_put_var_init): + { + int ret; + JSAtom atom; + atom = get_u32(pc); + pc += 4; + sf->cur_pc = pc; + + ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var); + sp--; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_put_var_strict): + { + int ret; + JSAtom atom; + atom = get_u32(pc); + pc += 4; + sf->cur_pc = pc; + + /* sp[-2] is JS_TRUE or JS_FALSE */ + if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) { + JS_ThrowReferenceErrorNotDefined(ctx, atom); + goto exception; + } + ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2); + sp -= 2; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_check_define_var): + { + JSAtom atom; + int flags; + atom = get_u32(pc); + flags = pc[4]; + pc += 5; + if (JS_CheckDefineGlobalVar(ctx, atom, flags)) + goto exception; + } + BREAK; + CASE(OP_define_var): + { + JSAtom atom; + int flags; + atom = get_u32(pc); + flags = pc[4]; + pc += 5; + if (JS_DefineGlobalVar(ctx, atom, flags)) + goto exception; + } + BREAK; + CASE(OP_define_func): + { + JSAtom atom; + int flags; + atom = get_u32(pc); + flags = pc[4]; + pc += 5; + if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp--; + } + BREAK; + + CASE(OP_get_loc): + { + int idx; + idx = get_u16(pc); + pc += 2; + sp[0] = js_dup(var_buf[idx]); + sp++; + } + BREAK; + CASE(OP_put_loc): + { + int idx; + idx = get_u16(pc); + pc += 2; + set_value(ctx, &var_buf[idx], sp[-1]); + sp--; + } + BREAK; + CASE(OP_set_loc): + { + int idx; + idx = get_u16(pc); + pc += 2; + set_value(ctx, &var_buf[idx], js_dup(sp[-1])); + } + BREAK; + CASE(OP_get_arg): + { + int idx; + idx = get_u16(pc); + pc += 2; + sp[0] = js_dup(arg_buf[idx]); + sp++; + } + BREAK; + CASE(OP_put_arg): + { + int idx; + idx = get_u16(pc); + pc += 2; + set_value(ctx, &arg_buf[idx], sp[-1]); + sp--; + } + BREAK; + CASE(OP_set_arg): + { + int idx; + idx = get_u16(pc); + pc += 2; + set_value(ctx, &arg_buf[idx], js_dup(sp[-1])); + } + BREAK; + + CASE(OP_get_loc8): *sp++ = js_dup(var_buf[*pc++]); BREAK; + CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK; + CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], js_dup(sp[-1])); BREAK; + + // Observation: get_loc0 and get_loc1 are individually very + // frequent opcodes _and_ they are very often paired together, + // making them ideal candidates for opcode fusion. + CASE(OP_get_loc0_loc1): + *sp++ = js_dup(var_buf[0]); + *sp++ = js_dup(var_buf[1]); + BREAK; + + CASE(OP_get_loc0): *sp++ = js_dup(var_buf[0]); BREAK; + CASE(OP_get_loc1): *sp++ = js_dup(var_buf[1]); BREAK; + CASE(OP_get_loc2): *sp++ = js_dup(var_buf[2]); BREAK; + CASE(OP_get_loc3): *sp++ = js_dup(var_buf[3]); BREAK; + CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK; + CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK; + CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK; + CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK; + CASE(OP_set_loc0): set_value(ctx, &var_buf[0], js_dup(sp[-1])); BREAK; + CASE(OP_set_loc1): set_value(ctx, &var_buf[1], js_dup(sp[-1])); BREAK; + CASE(OP_set_loc2): set_value(ctx, &var_buf[2], js_dup(sp[-1])); BREAK; + CASE(OP_set_loc3): set_value(ctx, &var_buf[3], js_dup(sp[-1])); BREAK; + CASE(OP_get_arg0): *sp++ = js_dup(arg_buf[0]); BREAK; + CASE(OP_get_arg1): *sp++ = js_dup(arg_buf[1]); BREAK; + CASE(OP_get_arg2): *sp++ = js_dup(arg_buf[2]); BREAK; + CASE(OP_get_arg3): *sp++ = js_dup(arg_buf[3]); BREAK; + CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK; + CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK; + CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK; + CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK; + CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], js_dup(sp[-1])); BREAK; + CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], js_dup(sp[-1])); BREAK; + CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], js_dup(sp[-1])); BREAK; + CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], js_dup(sp[-1])); BREAK; + CASE(OP_get_var_ref0): *sp++ = js_dup(*var_refs[0]->pvalue); BREAK; + CASE(OP_get_var_ref1): *sp++ = js_dup(*var_refs[1]->pvalue); BREAK; + CASE(OP_get_var_ref2): *sp++ = js_dup(*var_refs[2]->pvalue); BREAK; + CASE(OP_get_var_ref3): *sp++ = js_dup(*var_refs[3]->pvalue); BREAK; + CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK; + CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK; + CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK; + CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK; + CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, js_dup(sp[-1])); BREAK; + CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, js_dup(sp[-1])); BREAK; + CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, js_dup(sp[-1])); BREAK; + CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, js_dup(sp[-1])); BREAK; + + CASE(OP_get_var_ref): + { + int idx; + JSValue val; + idx = get_u16(pc); + pc += 2; + val = *var_refs[idx]->pvalue; + sp[0] = js_dup(val); + sp++; + } + BREAK; + CASE(OP_put_var_ref): + { + int idx; + idx = get_u16(pc); + pc += 2; + set_value(ctx, var_refs[idx]->pvalue, sp[-1]); + sp--; + } + BREAK; + CASE(OP_set_var_ref): + { + int idx; + idx = get_u16(pc); + pc += 2; + set_value(ctx, var_refs[idx]->pvalue, js_dup(sp[-1])); + } + BREAK; + CASE(OP_get_var_ref_check): + { + int idx; + JSValue val; + idx = get_u16(pc); + pc += 2; + val = *var_refs[idx]->pvalue; + if (unlikely(JS_IsUninitialized(val))) { + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, true); + goto exception; + } + sp[0] = js_dup(val); + sp++; + } + BREAK; + CASE(OP_put_var_ref_check): + { + int idx; + idx = get_u16(pc); + pc += 2; + if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) { + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, true); + goto exception; + } + set_value(ctx, var_refs[idx]->pvalue, sp[-1]); + sp--; + } + BREAK; + CASE(OP_put_var_ref_check_init): + { + int idx; + idx = get_u16(pc); + pc += 2; + if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) { + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, true); + goto exception; + } + set_value(ctx, var_refs[idx]->pvalue, sp[-1]); + sp--; + } + BREAK; + CASE(OP_set_loc_uninitialized): + { + int idx; + idx = get_u16(pc); + pc += 2; + set_value(ctx, &var_buf[idx], JS_UNINITIALIZED); + } + BREAK; + CASE(OP_get_loc_check): + { + int idx; + idx = get_u16(pc); + pc += 2; + if (unlikely(JS_IsUninitialized(var_buf[idx]))) { + JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, + false); + goto exception; + } + sp[0] = js_dup(var_buf[idx]); + sp++; + } + BREAK; + CASE(OP_put_loc_check): + { + int idx; + idx = get_u16(pc); + pc += 2; + if (unlikely(JS_IsUninitialized(var_buf[idx]))) { + JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, + false); + goto exception; + } + set_value(ctx, &var_buf[idx], sp[-1]); + sp--; + } + BREAK; + CASE(OP_put_loc_check_init): + { + int idx; + idx = get_u16(pc); + pc += 2; + if (unlikely(!JS_IsUninitialized(var_buf[idx]))) { + JS_ThrowReferenceError(caller_ctx, + "'this' can be initialized only once"); + goto exception; + } + set_value(ctx, &var_buf[idx], sp[-1]); + sp--; + } + BREAK; + CASE(OP_close_loc): + { + int idx; + idx = get_u16(pc); + pc += 2; + close_lexical_var(ctx, sf, idx); + } + BREAK; + + CASE(OP_make_loc_ref): + CASE(OP_make_arg_ref): + CASE(OP_make_var_ref_ref): + { + JSVarRef *var_ref; + JSProperty *pr; + JSAtom atom; + int idx; + atom = get_u32(pc); + idx = get_u16(pc + 4); + pc += 6; + *sp++ = JS_NewObjectProto(ctx, JS_NULL); + if (unlikely(JS_IsException(sp[-1]))) + goto exception; + if (opcode == OP_make_var_ref_ref) { + var_ref = var_refs[idx]; + var_ref->header.ref_count++; + } else { + var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref); + if (!var_ref) + goto exception; + } + pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom, + JS_PROP_WRITABLE | JS_PROP_VARREF); + if (!pr) { + free_var_ref(rt, var_ref); + goto exception; + } + pr->u.var_ref = var_ref; + *sp++ = JS_AtomToValue(ctx, atom); + } + BREAK; + CASE(OP_make_var_ref): + { + JSAtom atom; + atom = get_u32(pc); + pc += 4; + + if (JS_GetGlobalVarRef(ctx, atom, sp)) + goto exception; + sp += 2; + } + BREAK; + + CASE(OP_goto): + pc += (int32_t)get_u32(pc); + if (unlikely(js_poll_interrupts(ctx))) + goto exception; + BREAK; + CASE(OP_goto16): + pc += (int16_t)get_u16(pc); + if (unlikely(js_poll_interrupts(ctx))) + goto exception; + BREAK; + CASE(OP_goto8): + pc += (int8_t)pc[0]; + if (unlikely(js_poll_interrupts(ctx))) + goto exception; + BREAK; + CASE(OP_if_true): + { + int res; + JSValue op1; + + op1 = sp[-1]; + pc += 4; + if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { + res = JS_VALUE_GET_INT(op1); + } else { + res = JS_ToBoolFree(ctx, op1); + } + sp--; + if (res) { + pc += (int32_t)get_u32(pc - 4) - 4; + } + if (unlikely(js_poll_interrupts(ctx))) + goto exception; + } + BREAK; + CASE(OP_if_false): + { + int res; + JSValue op1; + + op1 = sp[-1]; + pc += 4; + if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { + res = JS_VALUE_GET_INT(op1); + } else { + res = JS_ToBoolFree(ctx, op1); + } + sp--; + if (!res) { + pc += (int32_t)get_u32(pc - 4) - 4; + } + if (unlikely(js_poll_interrupts(ctx))) + goto exception; + } + BREAK; + CASE(OP_if_true8): + { + int res; + JSValue op1; + + op1 = sp[-1]; + pc += 1; + if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { + res = JS_VALUE_GET_INT(op1); + } else { + res = JS_ToBoolFree(ctx, op1); + } + sp--; + if (res) { + pc += (int8_t)pc[-1] - 1; + } + if (unlikely(js_poll_interrupts(ctx))) + goto exception; + } + BREAK; + CASE(OP_if_false8): + { + int res; + JSValue op1; + + op1 = sp[-1]; + pc += 1; + if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { + res = JS_VALUE_GET_INT(op1); + } else { + res = JS_ToBoolFree(ctx, op1); + } + sp--; + if (!res) { + pc += (int8_t)pc[-1] - 1; + } + if (unlikely(js_poll_interrupts(ctx))) + goto exception; + } + BREAK; + CASE(OP_catch): + { + int32_t diff; + diff = get_u32(pc); + sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf); + sp++; + pc += 4; + } + BREAK; + CASE(OP_gosub): + { + int32_t diff; + diff = get_u32(pc); + /* XXX: should have a different tag to avoid security flaw */ + sp[0] = js_int32(pc + 4 - b->byte_code_buf); + sp++; + pc += diff; + } + BREAK; + CASE(OP_ret): + { + JSValue op1; + uint32_t pos; + op1 = sp[-1]; + if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT)) + goto ret_fail; + pos = JS_VALUE_GET_INT(op1); + if (unlikely(pos >= b->byte_code_len)) { + ret_fail: + JS_ThrowInternalError(ctx, "invalid ret value"); + goto exception; + } + sp--; + pc = b->byte_code_buf + pos; + } + BREAK; + + CASE(OP_for_in_start): + sf->cur_pc = pc; + if (js_for_in_start(ctx, sp)) + goto exception; + BREAK; + CASE(OP_for_in_next): + sf->cur_pc = pc; + if (js_for_in_next(ctx, sp)) + goto exception; + sp += 2; + BREAK; + CASE(OP_for_of_start): + sf->cur_pc = pc; + if (js_for_of_start(ctx, sp, false)) + goto exception; + sp += 1; + *sp++ = JS_NewCatchOffset(ctx, 0); + BREAK; + CASE(OP_for_of_next): + { + int offset = -3 - pc[0]; + pc += 1; + sf->cur_pc = pc; + if (js_for_of_next(ctx, sp, offset)) + goto exception; + sp += 2; + } + BREAK; + CASE(OP_for_await_of_start): + sf->cur_pc = pc; + if (js_for_of_start(ctx, sp, true)) + goto exception; + sp += 1; + *sp++ = JS_NewCatchOffset(ctx, 0); + BREAK; + CASE(OP_iterator_get_value_done): + sf->cur_pc = pc; + if (js_iterator_get_value_done(ctx, sp)) + goto exception; + sp += 1; + BREAK; + CASE(OP_iterator_check_object): + if (unlikely(!JS_IsObject(sp[-1]))) { + JS_ThrowTypeError(ctx, "iterator must return an object"); + goto exception; + } + BREAK; + + CASE(OP_iterator_close): + /* iter_obj next catch_offset -> */ + sp--; /* drop the catch offset to avoid getting caught by exception */ + JS_FreeValue(ctx, sp[-1]); /* drop the next method */ + sp--; + if (!JS_IsUndefined(sp[-1])) { + sf->cur_pc = pc; + if (JS_IteratorClose(ctx, sp[-1], false)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + } + sp--; + BREAK; + CASE(OP_nip_catch): + { + JSValue ret_val; + /* catch_offset ... ret_val -> ret_eval */ + ret_val = *--sp; + while (sp > stack_buf && + JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) { + JS_FreeValue(ctx, *--sp); + } + if (unlikely(sp == stack_buf)) { + JS_ThrowInternalError(ctx, "nip_catch"); + JS_FreeValue(ctx, ret_val); + goto exception; + } + sp[-1] = ret_val; + } + BREAK; + + CASE(OP_iterator_next): + /* stack: iter_obj next catch_offset val */ + { + JSValue ret; + sf->cur_pc = pc; + ret = JS_Call(ctx, sp[-3], sp[-4], 1, vc(sp - 1)); + if (JS_IsException(ret)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = ret; + } + BREAK; + + CASE(OP_iterator_call): + /* stack: iter_obj next catch_offset val */ + { + JSValue method, ret; + bool ret_flag; + int flags; + flags = *pc++; + sf->cur_pc = pc; + method = JS_GetProperty(ctx, sp[-4], (flags & 1) ? + JS_ATOM_throw : JS_ATOM_return); + if (JS_IsException(method)) + goto exception; + if (JS_IsUndefined(method) || JS_IsNull(method)) { + ret_flag = true; + } else { + if (flags & 2) { + /* no argument */ + ret = JS_CallFree(ctx, method, sp[-4], + 0, NULL); + } else { + ret = JS_CallFree(ctx, method, sp[-4], + 1, vc(sp - 1)); + } + if (JS_IsException(ret)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = ret; + ret_flag = false; + } + sp[0] = js_bool(ret_flag); + sp += 1; + } + BREAK; + + CASE(OP_lnot): + { + int res; + JSValue op1; + + op1 = sp[-1]; + if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { + res = JS_VALUE_GET_INT(op1) != 0; + } else { + res = JS_ToBoolFree(ctx, op1); + } + sp[-1] = js_bool(!res); + } + BREAK; + + CASE(OP_get_field): + { + JSValue val; + JSAtom atom; + atom = get_u32(pc); + pc += 4; + sf->cur_pc = pc; + val = JS_GetPropertyInternal(ctx, sp[-1], atom, sp[-1], false); + if (unlikely(JS_IsException(val))) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = val; + } + BREAK; + + CASE(OP_get_field2): + { + JSValue val; + JSAtom atom; + atom = get_u32(pc); + pc += 4; + sf->cur_pc = pc; + val = JS_GetPropertyInternal(ctx, sp[-1], atom, sp[-1], false); + if (unlikely(JS_IsException(val))) + goto exception; + *sp++ = val; + } + BREAK; + + CASE(OP_put_field): + { + int ret; + JSAtom atom; + atom = get_u32(pc); + pc += 4; + sf->cur_pc = pc; + ret = JS_SetPropertyInternal2(ctx, + sp[-2], atom, + sp[-1], sp[-2], + JS_PROP_THROW_STRICT); + JS_FreeValue(ctx, sp[-2]); + sp -= 2; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_private_symbol): + { + JSAtom atom; + JSValue val; + + atom = get_u32(pc); + pc += 4; + val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE); + if (JS_IsException(val)) + goto exception; + *sp++ = val; + } + BREAK; + + CASE(OP_get_private_field): + { + JSValue val; + sf->cur_pc = pc; + val = JS_GetPrivateField(ctx, sp[-2], sp[-1]); + JS_FreeValue(ctx, sp[-1]); + JS_FreeValue(ctx, sp[-2]); + sp[-2] = val; + sp--; + if (unlikely(JS_IsException(val))) + goto exception; + } + BREAK; + + CASE(OP_put_private_field): + { + int ret; + sf->cur_pc = pc; + ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]); + JS_FreeValue(ctx, sp[-3]); + JS_FreeValue(ctx, sp[-1]); + sp -= 3; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_define_private_field): + { + int ret; + ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]); + JS_FreeValue(ctx, sp[-2]); + sp -= 2; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_define_field): + { + int ret; + JSAtom atom; + atom = get_u32(pc); + pc += 4; + + ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1], + JS_PROP_C_W_E | JS_PROP_THROW); + sp--; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_set_name): + { + int ret; + JSAtom atom; + atom = get_u32(pc); + pc += 4; + + ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE); + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + CASE(OP_set_name_computed): + { + int ret; + ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE); + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + CASE(OP_set_proto): + { + JSValue proto; + proto = sp[-1]; + if (JS_IsObject(proto) || JS_IsNull(proto)) { + if (JS_SetPrototypeInternal(ctx, sp[-2], proto, true) < 0) + goto exception; + } + JS_FreeValue(ctx, proto); + sp--; + } + BREAK; + CASE(OP_set_home_object): + js_method_set_home_object(ctx, sp[-1], sp[-2]); + BREAK; + CASE(OP_define_method): + CASE(OP_define_method_computed): + { + JSValue getter, setter, value; + JSValue obj; + JSAtom atom; + int flags, ret, op_flags; + bool is_computed; +#define OP_DEFINE_METHOD_METHOD 0 +#define OP_DEFINE_METHOD_GETTER 1 +#define OP_DEFINE_METHOD_SETTER 2 +#define OP_DEFINE_METHOD_ENUMERABLE 4 + + is_computed = (opcode == OP_define_method_computed); + if (is_computed) { + atom = JS_ValueToAtom(ctx, sp[-2]); + if (unlikely(atom == JS_ATOM_NULL)) + goto exception; + opcode += OP_define_method - OP_define_method_computed; + } else { + atom = get_u32(pc); + pc += 4; + } + op_flags = *pc++; + + obj = sp[-2 - is_computed]; + flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE | + JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW; + if (op_flags & OP_DEFINE_METHOD_ENUMERABLE) + flags |= JS_PROP_ENUMERABLE; + op_flags &= 3; + value = JS_UNDEFINED; + getter = JS_UNDEFINED; + setter = JS_UNDEFINED; + if (op_flags == OP_DEFINE_METHOD_METHOD) { + value = sp[-1]; + flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE; + } else if (op_flags == OP_DEFINE_METHOD_GETTER) { + getter = sp[-1]; + flags |= JS_PROP_HAS_GET; + } else { + setter = sp[-1]; + flags |= JS_PROP_HAS_SET; + } + ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj); + if (ret >= 0) { + ret = JS_DefineProperty(ctx, obj, atom, value, + getter, setter, flags); + } + JS_FreeValue(ctx, sp[-1]); + if (is_computed) { + JS_FreeAtom(ctx, atom); + JS_FreeValue(ctx, sp[-2]); + } + sp -= 1 + is_computed; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_define_class): + CASE(OP_define_class_computed): + { + int class_flags; + JSAtom atom; + + atom = get_u32(pc); + class_flags = pc[4]; + pc += 5; + if (js_op_define_class(ctx, sp, atom, class_flags, + var_refs, sf, + (opcode == OP_define_class_computed)) < 0) + goto exception; + } + BREAK; + + CASE(OP_get_array_el): + { + JSValue val; + + sf->cur_pc = pc; + val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); + JS_FreeValue(ctx, sp[-2]); + sp[-2] = val; + sp--; + if (unlikely(JS_IsException(val))) + goto exception; + } + BREAK; + + CASE(OP_get_array_el2): + { + JSValue val; + + sf->cur_pc = pc; + val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); + sp[-1] = val; + if (unlikely(JS_IsException(val))) + goto exception; + } + BREAK; + + CASE(OP_get_ref_value): + { + JSValue val; + sf->cur_pc = pc; + if (unlikely(JS_IsUndefined(sp[-2]))) { + JSAtom atom = JS_ValueToAtom(ctx, sp[-1]); + if (atom != JS_ATOM_NULL) { + JS_ThrowReferenceErrorNotDefined(ctx, atom); + JS_FreeAtom(ctx, atom); + } + goto exception; + } + val = JS_GetPropertyValue(ctx, sp[-2], + js_dup(sp[-1])); + if (unlikely(JS_IsException(val))) + goto exception; + sp[0] = val; + sp++; + } + BREAK; + + CASE(OP_get_super_value): + { + JSValue val; + JSAtom atom; + sf->cur_pc = pc; + atom = JS_ValueToAtom(ctx, sp[-1]); + if (unlikely(atom == JS_ATOM_NULL)) + goto exception; + val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], false); + JS_FreeAtom(ctx, atom); + if (unlikely(JS_IsException(val))) + goto exception; + JS_FreeValue(ctx, sp[-1]); + JS_FreeValue(ctx, sp[-2]); + JS_FreeValue(ctx, sp[-3]); + sp[-3] = val; + sp -= 2; + } + BREAK; + + CASE(OP_put_array_el): + { + int ret; + sf->cur_pc = pc; + ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT); + JS_FreeValue(ctx, sp[-3]); + sp -= 3; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_put_ref_value): + { + int ret, flags; + sf->cur_pc = pc; + flags = JS_PROP_THROW_STRICT; + if (unlikely(JS_IsUndefined(sp[-3]))) { + if (is_strict_mode(ctx)) { + JSAtom atom = JS_ValueToAtom(ctx, sp[-2]); + if (atom != JS_ATOM_NULL) { + JS_ThrowReferenceErrorNotDefined(ctx, atom); + JS_FreeAtom(ctx, atom); + } + goto exception; + } else { + sp[-3] = js_dup(ctx->global_obj); + } + } else { + if (is_strict_mode(ctx)) + flags |= JS_PROP_NO_ADD; + } + ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags); + JS_FreeValue(ctx, sp[-3]); + sp -= 3; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_put_super_value): + { + int ret; + JSAtom atom; + sf->cur_pc = pc; + if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) { + JS_ThrowTypeErrorNotAnObject(ctx); + goto exception; + } + atom = JS_ValueToAtom(ctx, sp[-2]); + if (unlikely(atom == JS_ATOM_NULL)) + goto exception; + ret = JS_SetPropertyInternal2(ctx, + sp[-3], atom, + sp[-1], sp[-4], + JS_PROP_THROW_STRICT); + JS_FreeAtom(ctx, atom); + JS_FreeValue(ctx, sp[-4]); + JS_FreeValue(ctx, sp[-3]); + JS_FreeValue(ctx, sp[-2]); + sp -= 4; + if (ret < 0) + goto exception; + } + BREAK; + + CASE(OP_define_array_el): + { + int ret; + ret = JS_DefinePropertyValueValue(ctx, sp[-3], js_dup(sp[-2]), sp[-1], + JS_PROP_C_W_E | JS_PROP_THROW); + sp -= 1; + if (unlikely(ret < 0)) + goto exception; + } + BREAK; + + CASE(OP_append): /* array pos enumobj -- array pos */ + { + sf->cur_pc = pc; + if (js_append_enumerate(ctx, sp)) + goto exception; + JS_FreeValue(ctx, *--sp); + } + BREAK; + + CASE(OP_copy_data_properties): /* target source excludeList */ + { + /* stack offsets (-1 based): + 2 bits for target, + 3 bits for source, + 2 bits for exclusionList */ + int mask; + + mask = *pc++; + sf->cur_pc = pc; + if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)], + sp[-1 - ((mask >> 2) & 7)], + sp[-1 - ((mask >> 5) & 7)], 0)) + goto exception; + } + BREAK; + + CASE(OP_add): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + int64_t r; + r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2); + if (unlikely((int)r != r)) + goto add_slow; + sp[-2] = js_int32(r); + sp--; + } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { + JS_X87_FPCW_SAVE_AND_ADJUST(fpcw); + sp[-2] = js_float64(JS_VALUE_GET_FLOAT64(op1) + + JS_VALUE_GET_FLOAT64(op2)); + JS_X87_FPCW_RESTORE(fpcw); + sp--; + } else { + add_slow: + sf->cur_pc = pc; + if (js_add_slow(ctx, sp)) + goto exception; + sp--; + } + } + BREAK; + CASE(OP_add_loc): + { + JSValue *pv; + int idx; + idx = *pc; + pc += 1; + + pv = &var_buf[idx]; + if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) { + int64_t r; + r = (int64_t)JS_VALUE_GET_INT(*pv) + + JS_VALUE_GET_INT(sp[-1]); + if (unlikely((int)r != r)) + goto add_loc_slow; + *pv = js_int32(r); + sp--; + } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) { + JSValue op1; + op1 = sp[-1]; + sp--; + sf->cur_pc = pc; + op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); + if (JS_IsException(op1)) + goto exception; + op1 = JS_ConcatString(ctx, js_dup(*pv), op1); + if (JS_IsException(op1)) + goto exception; + set_value(ctx, pv, op1); + } else { + JSValue ops[2]; + add_loc_slow: + /* In case of exception, js_add_slow frees ops[0] + and ops[1], so we must duplicate *pv */ + sf->cur_pc = pc; + ops[0] = js_dup(*pv); + ops[1] = sp[-1]; + sp--; + if (js_add_slow(ctx, ops + 2)) + goto exception; + set_value(ctx, pv, ops[0]); + } + } + BREAK; + CASE(OP_sub): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + int64_t r; + r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2); + if (unlikely((int)r != r)) + goto binary_arith_slow; + sp[-2] = js_int32(r); + sp--; + } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { + JS_X87_FPCW_SAVE_AND_ADJUST(fpcw); + sp[-2] = js_float64(JS_VALUE_GET_FLOAT64(op1) - + JS_VALUE_GET_FLOAT64(op2)); + JS_X87_FPCW_RESTORE(fpcw); + sp--; + } else { + goto binary_arith_slow; + } + } + BREAK; + CASE(OP_mul): + { + JSValue op1, op2; + double d; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + int32_t v1, v2; + int64_t r; + v1 = JS_VALUE_GET_INT(op1); + v2 = JS_VALUE_GET_INT(op2); + r = (int64_t)v1 * v2; + if (unlikely((int)r != r)) { + d = (double)r; + goto mul_fp_res; + } + /* need to test zero case for -0 result */ + if (unlikely(r == 0 && (v1 | v2) < 0)) { + d = -0.0; + goto mul_fp_res; + } + sp[-2] = js_int32(r); + sp--; + } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { + JS_X87_FPCW_SAVE_AND_ADJUST(fpcw); + d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2); + JS_X87_FPCW_RESTORE(fpcw); + mul_fp_res: + sp[-2] = js_float64(d); + sp--; + } else { + goto binary_arith_slow; + } + } + BREAK; + CASE(OP_div): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + int v1, v2; + v1 = JS_VALUE_GET_INT(op1); + v2 = JS_VALUE_GET_INT(op2); + sp[-2] = js_number((double)v1 / (double)v2); + sp--; + } else { + goto binary_arith_slow; + } + } + BREAK; + CASE(OP_mod): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + int v1, v2, r; + v1 = JS_VALUE_GET_INT(op1); + v2 = JS_VALUE_GET_INT(op2); + /* We must avoid v2 = 0, v1 = INT32_MIN and v2 = + -1 and the cases where the result is -0. */ + if (unlikely(v1 < 0 || v2 <= 0)) + goto binary_arith_slow; + r = v1 % v2; + sp[-2] = js_int32(r); + sp--; + } else { + goto binary_arith_slow; + } + } + BREAK; + CASE(OP_pow): + binary_arith_slow: + sf->cur_pc = pc; + if (js_binary_arith_slow(ctx, sp, opcode)) + goto exception; + sp--; + BREAK; + + CASE(OP_plus): + { + JSValue op1; + uint32_t tag; + op1 = sp[-1]; + tag = JS_VALUE_GET_TAG(op1); + if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) { + } else { + sf->cur_pc = pc; + if (js_unary_arith_slow(ctx, sp, opcode)) + goto exception; + } + } + BREAK; + CASE(OP_neg): + { + JSValue op1; + uint32_t tag; + int val; + double d; + op1 = sp[-1]; + tag = JS_VALUE_GET_TAG(op1); + if (tag == JS_TAG_INT) { + val = JS_VALUE_GET_INT(op1); + /* Note: -0 cannot be expressed as integer */ + if (unlikely(val == 0)) { + d = -0.0; + goto neg_fp_res; + } + if (unlikely(val == INT32_MIN)) { + d = -(double)val; + goto neg_fp_res; + } + sp[-1] = js_int32(-val); + } else if (JS_TAG_IS_FLOAT64(tag)) { + d = -JS_VALUE_GET_FLOAT64(op1); + neg_fp_res: + sp[-1] = js_float64(d); + } else { + sf->cur_pc = pc; + if (js_unary_arith_slow(ctx, sp, opcode)) + goto exception; + } + } + BREAK; + CASE(OP_inc): + { + JSValue op1; + int val; + op1 = sp[-1]; + if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { + val = JS_VALUE_GET_INT(op1); + if (unlikely(val == INT32_MAX)) + goto inc_slow; + sp[-1] = js_int32(val + 1); + } else { + inc_slow: + sf->cur_pc = pc; + if (js_unary_arith_slow(ctx, sp, opcode)) + goto exception; + } + } + BREAK; + CASE(OP_dec): + { + JSValue op1; + int val; + op1 = sp[-1]; + if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { + val = JS_VALUE_GET_INT(op1); + if (unlikely(val == INT32_MIN)) + goto dec_slow; + sp[-1] = js_int32(val - 1); + } else { + dec_slow: + sf->cur_pc = pc; + if (js_unary_arith_slow(ctx, sp, opcode)) + goto exception; + } + } + BREAK; + CASE(OP_post_inc): + CASE(OP_post_dec): + sf->cur_pc = pc; + if (js_post_inc_slow(ctx, sp, opcode)) + goto exception; + sp++; + BREAK; + CASE(OP_inc_loc): + { + JSValue op1; + int val; + int idx; + idx = *pc; + pc += 1; + + op1 = var_buf[idx]; + if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { + val = JS_VALUE_GET_INT(op1); + if (unlikely(val == INT32_MAX)) + goto inc_loc_slow; + var_buf[idx] = js_int32(val + 1); + } else { + inc_loc_slow: + sf->cur_pc = pc; + /* must duplicate otherwise the variable value may + be destroyed before JS code accesses it */ + op1 = js_dup(op1); + if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc)) + goto exception; + set_value(ctx, &var_buf[idx], op1); + } + } + BREAK; + CASE(OP_dec_loc): + { + JSValue op1; + int val; + int idx; + idx = *pc; + pc += 1; + + op1 = var_buf[idx]; + if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { + val = JS_VALUE_GET_INT(op1); + if (unlikely(val == INT32_MIN)) + goto dec_loc_slow; + var_buf[idx] = js_int32(val - 1); + } else { + dec_loc_slow: + sf->cur_pc = pc; + /* must duplicate otherwise the variable value may + be destroyed before JS code accesses it */ + op1 = js_dup(op1); + if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec)) + goto exception; + set_value(ctx, &var_buf[idx], op1); + } + } + BREAK; + CASE(OP_not): + { + JSValue op1; + op1 = sp[-1]; + if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { + sp[-1] = js_int32(~JS_VALUE_GET_INT(op1)); + } else { + sf->cur_pc = pc; + if (js_not_slow(ctx, sp)) + goto exception; + } + } + BREAK; + + CASE(OP_shl): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + uint32_t v1, v2; + v1 = JS_VALUE_GET_INT(op1); + v2 = JS_VALUE_GET_INT(op2) & 0x1f; + sp[-2] = js_int32(v1 << v2); + sp--; + } else { + sf->cur_pc = pc; + if (js_binary_logic_slow(ctx, sp, opcode)) + goto exception; + sp--; + } + } + BREAK; + CASE(OP_shr): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + uint32_t v2; + v2 = JS_VALUE_GET_INT(op2); + v2 &= 0x1f; + sp[-2] = js_uint32((uint32_t)JS_VALUE_GET_INT(op1) >> v2); + sp--; + } else { + sf->cur_pc = pc; + if (js_shr_slow(ctx, sp)) + goto exception; + sp--; + } + } + BREAK; + CASE(OP_sar): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + uint32_t v2; + v2 = JS_VALUE_GET_INT(op2); + if (unlikely(v2 > 0x1f)) { + v2 &= 0x1f; + } + sp[-2] = js_int32((int)JS_VALUE_GET_INT(op1) >> v2); + sp--; + } else { + sf->cur_pc = pc; + if (js_binary_logic_slow(ctx, sp, opcode)) + goto exception; + sp--; + } + } + BREAK; + CASE(OP_and): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + sp[-2] = js_int32(JS_VALUE_GET_INT(op1) & JS_VALUE_GET_INT(op2)); + sp--; + } else { + sf->cur_pc = pc; + if (js_binary_logic_slow(ctx, sp, opcode)) + goto exception; + sp--; + } + } + BREAK; + CASE(OP_or): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + sp[-2] = js_int32(JS_VALUE_GET_INT(op1) | JS_VALUE_GET_INT(op2)); + sp--; + } else { + sf->cur_pc = pc; + if (js_binary_logic_slow(ctx, sp, opcode)) + goto exception; + sp--; + } + } + BREAK; + CASE(OP_xor): + { + JSValue op1, op2; + op1 = sp[-2]; + op2 = sp[-1]; + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { + sp[-2] = js_int32(JS_VALUE_GET_INT(op1) ^ JS_VALUE_GET_INT(op2)); + sp--; + } else { + sf->cur_pc = pc; + if (js_binary_logic_slow(ctx, sp, opcode)) + goto exception; + sp--; + } + } + BREAK; + + +#define OP_CMP(opcode, binary_op, slow_call) \ + CASE(opcode): \ + { \ + JSValue op1, op2; \ + op1 = sp[-2]; \ + op2 = sp[-1]; \ + if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { \ + sp[-2] = js_bool(JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \ + sp--; \ + } else { \ + sf->cur_pc = pc; \ + if (slow_call) \ + goto exception; \ + sp--; \ + } \ + } \ + BREAK + + OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode)); + OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode)); + OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode)); + OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode)); + OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0)); + OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1)); + OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0)); + OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1)); + + CASE(OP_in): + sf->cur_pc = pc; + if (js_operator_in(ctx, sp)) + goto exception; + sp--; + BREAK; + CASE(OP_private_in): + if (js_operator_private_in(ctx, sp)) + goto exception; + sp--; + BREAK; + CASE(OP_instanceof): + sf->cur_pc = pc; + if (js_operator_instanceof(ctx, sp)) + goto exception; + sp--; + BREAK; + CASE(OP_typeof): + { + JSValue op1; + JSAtom atom; + + op1 = sp[-1]; + atom = js_operator_typeof(ctx, op1); + JS_FreeValue(ctx, op1); + sp[-1] = JS_AtomToString(ctx, atom); + } + BREAK; + CASE(OP_delete): + sf->cur_pc = pc; + if (js_operator_delete(ctx, sp)) + goto exception; + sp--; + BREAK; + CASE(OP_delete_var): + { + JSAtom atom; + int ret; + + atom = get_u32(pc); + pc += 4; + + sf->cur_pc = pc; + ret = JS_DeleteGlobalVar(ctx, atom); + if (unlikely(ret < 0)) + goto exception; + *sp++ = js_bool(ret); + } + BREAK; + + CASE(OP_to_object): + if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) { + sf->cur_pc = pc; + ret_val = JS_ToObject(ctx, sp[-1]); + if (JS_IsException(ret_val)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = ret_val; + } + BREAK; + + CASE(OP_to_propkey): + switch (JS_VALUE_GET_TAG(sp[-1])) { + case JS_TAG_INT: + case JS_TAG_STRING: + case JS_TAG_SYMBOL: + break; + default: + sf->cur_pc = pc; + ret_val = JS_ToPropertyKey(ctx, sp[-1]); + if (JS_IsException(ret_val)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = ret_val; + break; + } + BREAK; + + CASE(OP_to_propkey2): + /* must be tested first */ + if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) { + JS_ThrowTypeError(ctx, "value has no property"); + goto exception; + } + switch (JS_VALUE_GET_TAG(sp[-1])) { + case JS_TAG_INT: + case JS_TAG_STRING: + case JS_TAG_SYMBOL: + break; + default: + sf->cur_pc = pc; + ret_val = JS_ToPropertyKey(ctx, sp[-1]); + if (JS_IsException(ret_val)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = ret_val; + break; + } + BREAK; + CASE(OP_with_get_var): + CASE(OP_with_put_var): + CASE(OP_with_delete_var): + CASE(OP_with_make_ref): + CASE(OP_with_get_ref): + CASE(OP_with_get_ref_undef): + { + JSAtom atom; + int32_t diff; + JSValue obj, val; + int ret, is_with; + atom = get_u32(pc); + diff = get_u32(pc + 4); + is_with = pc[8]; + pc += 9; + sf->cur_pc = pc; + + obj = sp[-1]; + ret = JS_HasProperty(ctx, obj, atom); + if (unlikely(ret < 0)) + goto exception; + if (ret) { + if (is_with) { + ret = js_has_unscopable(ctx, obj, atom); + if (unlikely(ret < 0)) + goto exception; + if (ret) + goto no_with; + } + switch (opcode) { + case OP_with_get_var: + val = JS_GetProperty(ctx, obj, atom); + if (unlikely(JS_IsException(val))) + goto exception; + set_value(ctx, &sp[-1], val); + break; + case OP_with_put_var: + /* XXX: check if strict mode */ + ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], + JS_PROP_THROW_STRICT); + JS_FreeValue(ctx, sp[-1]); + sp -= 2; + if (unlikely(ret < 0)) + goto exception; + break; + case OP_with_delete_var: + ret = JS_DeleteProperty(ctx, obj, atom, 0); + if (unlikely(ret < 0)) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = js_bool(ret); + break; + case OP_with_make_ref: + /* produce a pair object/propname on the stack */ + *sp++ = JS_AtomToValue(ctx, atom); + break; + case OP_with_get_ref: + /* produce a pair object/method on the stack */ + val = JS_GetProperty(ctx, obj, atom); + if (unlikely(JS_IsException(val))) + goto exception; + *sp++ = val; + break; + case OP_with_get_ref_undef: + /* produce a pair undefined/function on the stack */ + val = JS_GetProperty(ctx, obj, atom); + if (unlikely(JS_IsException(val))) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = JS_UNDEFINED; + *sp++ = val; + break; + } + pc += diff - 5; + } else { + no_with: + /* if not jumping, drop the object argument */ + JS_FreeValue(ctx, sp[-1]); + sp--; + } + } + BREAK; + + CASE(OP_await): + ret_val = js_int32(FUNC_RET_AWAIT); + goto done_generator; + CASE(OP_yield): + ret_val = js_int32(FUNC_RET_YIELD); + goto done_generator; + CASE(OP_yield_star): + CASE(OP_async_yield_star): + ret_val = js_int32(FUNC_RET_YIELD_STAR); + goto done_generator; + CASE(OP_return_async): + CASE(OP_initial_yield): + ret_val = JS_UNDEFINED; + goto done_generator; + + CASE(OP_nop): + BREAK; + CASE(OP_is_undefined_or_null): + if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED || + JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) { + goto set_true; + } else { + goto free_and_set_false; + } + CASE(OP_is_undefined): + if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) { + goto set_true; + } else { + goto free_and_set_false; + } + CASE(OP_is_null): + if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) { + goto set_true; + } else { + goto free_and_set_false; + } + /* XXX: could merge to a single opcode */ + CASE(OP_typeof_is_undefined): + /* different from OP_is_undefined because of isHTMLDDA */ + if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) { + goto free_and_set_true; + } else { + goto free_and_set_false; + } + CASE(OP_typeof_is_function): + if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) { + goto free_and_set_true; + } else { + goto free_and_set_false; + } + free_and_set_true: + JS_FreeValue(ctx, sp[-1]); + set_true: + sp[-1] = JS_TRUE; + BREAK; + free_and_set_false: + JS_FreeValue(ctx, sp[-1]); + sp[-1] = JS_FALSE; + BREAK; + CASE(OP_invalid): + DEFAULT: + JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x", + (int)(pc - b->byte_code_buf - 1), opcode); + goto exception; + } + } + exception: + if (needs_backtrace(rt->current_exception) + || JS_IsUndefined(ctx->error_back_trace)) { + sf->cur_pc = pc; + build_backtrace(ctx, rt->current_exception, JS_UNDEFINED, + NULL, 0, 0, 0); + } + if (!JS_IsUncatchableError(rt->current_exception)) { + while (sp > stack_buf) { + JSValue val = *--sp; + JS_FreeValue(ctx, val); + if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) { + int pos = JS_VALUE_GET_INT(val); + if (pos == 0) { + /* enumerator: close it with a throw */ + JS_FreeValue(ctx, sp[-1]); /* drop the next method */ + sp--; + JS_IteratorClose(ctx, sp[-1], true); + } else { + *sp++ = rt->current_exception; + rt->current_exception = JS_UNINITIALIZED; + JS_FreeValueRT(rt, ctx->error_back_trace); + ctx->error_back_trace = JS_UNDEFINED; + pc = b->byte_code_buf + pos; + goto restart; + } + } + } + } + ret_val = JS_EXCEPTION; + /* the local variables are freed by the caller in the generator + case. Hence the label 'done' should never be reached in a + generator function. */ + if (b->func_kind != JS_FUNC_NORMAL) { + done_generator: + sf->cur_pc = pc; + sf->cur_sp = sp; + } else { + done: + if (unlikely(!list_empty(&sf->var_ref_list))) { + /* variable references reference the stack: must close them */ + close_var_refs(rt, sf); + } + /* free the local variables and stack */ + for(pval = local_buf; pval < sp; pval++) { + JS_FreeValue(ctx, *pval); + } + } + rt->current_stack_frame = sf->prev_frame; + return ret_val; +} + +JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, + int argc, JSValueConst *argv) +{ + return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, + argc, argv, JS_CALL_FLAG_COPY_ARGV); +} + +static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, + int argc, JSValueConst *argv) +{ + JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, + argc, argv, JS_CALL_FLAG_COPY_ARGV); + JS_FreeValue(ctx, func_obj); + return res; +} + +/* warning: the refcount of the context is not incremented. Return + NULL in case of exception (case of revoked proxy only) */ +static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj) +{ + JSObject *p; + JSContext *realm; + + if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) + return ctx; + p = JS_VALUE_GET_OBJ(func_obj); + switch(p->class_id) { + case JS_CLASS_C_FUNCTION: + realm = p->u.cfunc.realm; + break; + case JS_CLASS_BYTECODE_FUNCTION: + case JS_CLASS_GENERATOR_FUNCTION: + case JS_CLASS_ASYNC_FUNCTION: + case JS_CLASS_ASYNC_GENERATOR_FUNCTION: + { + JSFunctionBytecode *b; + b = p->u.func.function_bytecode; + realm = b->realm; + } + break; + case JS_CLASS_PROXY: + { + JSProxyData *s = p->u.opaque; + if (!s) + return ctx; + if (s->is_revoked) { + JS_ThrowTypeErrorRevokedProxy(ctx); + return NULL; + } else { + realm = JS_GetFunctionRealm(ctx, s->target); + } + } + break; + case JS_CLASS_BOUND_FUNCTION: + { + JSBoundFunction *bf = p->u.bound_function; + realm = JS_GetFunctionRealm(ctx, bf->func_obj); + } + break; + default: + realm = ctx; + break; + } + return realm; +} + +static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor, + int class_id) +{ + JSValue proto, obj; + JSContext *realm; + + if (JS_IsUndefined(ctor)) { + proto = js_dup(ctx->class_proto[class_id]); + } else { + proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype); + if (JS_IsException(proto)) + return proto; + if (!JS_IsObject(proto)) { + JS_FreeValue(ctx, proto); + realm = JS_GetFunctionRealm(ctx, ctor); + if (!realm) + return JS_EXCEPTION; + proto = js_dup(realm->class_proto[class_id]); + } + } + obj = JS_NewObjectProtoClass(ctx, proto, class_id); + JS_FreeValue(ctx, proto); + return obj; +} + +/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ +static JSValue JS_CallConstructorInternal(JSContext *ctx, + JSValueConst func_obj, + JSValueConst new_target, + int argc, JSValueConst *argv, + int flags) +{ + JSObject *p; + JSFunctionBytecode *b; + + if (js_poll_interrupts(ctx)) + return JS_EXCEPTION; + flags |= JS_CALL_FLAG_CONSTRUCTOR; + if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) + goto not_a_function; + p = JS_VALUE_GET_OBJ(func_obj); + if (unlikely(!p->is_constructor)) + return JS_ThrowTypeErrorNotAConstructor(ctx, func_obj); + if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) { + JSClassCall *call_func; + call_func = ctx->rt->class_array[p->class_id].call; + if (!call_func) { + not_a_function: + return JS_ThrowTypeErrorNotAFunction(ctx); + } + return call_func(ctx, func_obj, new_target, argc, + argv, flags); + } + + b = p->u.func.function_bytecode; + if (b->is_derived_class_constructor) { + return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags); + } else { + JSValue obj, ret; + /* legacy constructor behavior */ + obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT); + if (JS_IsException(obj)) + return JS_EXCEPTION; + ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags); + if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT || + JS_IsException(ret)) { + JS_FreeValue(ctx, obj); + return ret; + } else { + JS_FreeValue(ctx, ret); + return obj; + } + } +} + +JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, + JSValueConst new_target, + int argc, JSValueConst *argv) +{ + return JS_CallConstructorInternal(ctx, func_obj, new_target, + argc, argv, + JS_CALL_FLAG_COPY_ARGV); +} + +JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, + int argc, JSValueConst *argv) +{ + return JS_CallConstructorInternal(ctx, func_obj, func_obj, + argc, argv, + JS_CALL_FLAG_COPY_ARGV); +} + +JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, + int argc, JSValueConst *argv) +{ + JSValue func_obj; + func_obj = JS_GetProperty(ctx, this_val, atom); + if (JS_IsException(func_obj)) + return func_obj; + return JS_CallFree(ctx, func_obj, this_val, argc, argv); +} + +static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, + int argc, JSValueConst *argv) +{ + JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv); + JS_FreeValue(ctx, this_val); + return res; +} + +/* JSAsyncFunctionState (used by generator and async functions) */ +static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s, + JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv) +{ + JSObject *p; + JSFunctionBytecode *b; + JSStackFrame *sf; + int local_count, i, arg_buf_len, n; + + sf = &s->frame; + init_list_head(&sf->var_ref_list); + p = JS_VALUE_GET_OBJ(func_obj); + b = p->u.func.function_bytecode; + sf->is_strict_mode = b->is_strict_mode; + sf->cur_pc = b->byte_code_buf; + arg_buf_len = max_int(b->arg_count, argc); + local_count = arg_buf_len + b->var_count + b->stack_size; + sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1)); + if (!sf->arg_buf) + return -1; + sf->cur_func = js_dup(func_obj); + s->this_val = js_dup(this_obj); + s->argc = argc; + sf->arg_count = arg_buf_len; + sf->var_buf = sf->arg_buf + arg_buf_len; + sf->cur_sp = sf->var_buf + b->var_count; + for(i = 0; i < argc; i++) + sf->arg_buf[i] = js_dup(argv[i]); + n = arg_buf_len + b->var_count; + for(i = argc; i < n; i++) + sf->arg_buf[i] = JS_UNDEFINED; + return 0; +} + +static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s, + JS_MarkFunc *mark_func) +{ + JSStackFrame *sf; + JSValue *sp; + + sf = &s->frame; + JS_MarkValue(rt, sf->cur_func, mark_func); + JS_MarkValue(rt, s->this_val, mark_func); + if (sf->cur_sp) { + /* if the function is running, cur_sp is not known so we + cannot mark the stack. Marking the variables is not needed + because a running function cannot be part of a removable + cycle */ + for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) + JS_MarkValue(rt, *sp, mark_func); + } +} + +static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) +{ + JSStackFrame *sf; + JSValue *sp; + + sf = &s->frame; + + /* close the closure variables. */ + close_var_refs(rt, sf); + + if (sf->arg_buf) { + /* cannot free the function if it is running */ + assert(sf->cur_sp != NULL); + for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) { + JS_FreeValueRT(rt, *sp); + } + js_free_rt(rt, sf->arg_buf); + } + JS_FreeValueRT(rt, sf->cur_func); + JS_FreeValueRT(rt, s->this_val); +} + +static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s) +{ + JSValue func_obj; + + if (js_check_stack_overflow(ctx->rt, 0)) + return JS_ThrowStackOverflow(ctx); + + /* the tag does not matter provided it is not an object */ + func_obj = JS_MKPTR(JS_TAG_INT, s); + return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, + s->argc, vc(s->frame.arg_buf), + JS_CALL_FLAG_GENERATOR); +} + + +/* Generators */ + +typedef enum JSGeneratorStateEnum { + JS_GENERATOR_STATE_SUSPENDED_START, + JS_GENERATOR_STATE_SUSPENDED_YIELD, + JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR, + JS_GENERATOR_STATE_EXECUTING, + JS_GENERATOR_STATE_COMPLETED, +} JSGeneratorStateEnum; + +typedef struct JSGeneratorData { + JSGeneratorStateEnum state; + JSAsyncFunctionState func_state; +} JSGeneratorData; + +static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s) +{ + if (s->state == JS_GENERATOR_STATE_COMPLETED) + return; + async_func_free(rt, &s->func_state); + s->state = JS_GENERATOR_STATE_COMPLETED; +} + +static void js_generator_finalizer(JSRuntime *rt, JSValueConst obj) +{ + JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR); + + if (s) { + free_generator_stack_rt(rt, s); + js_free_rt(rt, s); + } +} + +static void free_generator_stack(JSContext *ctx, JSGeneratorData *s) +{ + free_generator_stack_rt(ctx->rt, s); +} + +static void js_generator_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSGeneratorData *s = p->u.generator_data; + + if (!s || s->state == JS_GENERATOR_STATE_COMPLETED) + return; + async_func_mark(rt, &s->func_state, mark_func); +} + +/* XXX: use enum */ +#define GEN_MAGIC_NEXT 0 +#define GEN_MAGIC_RETURN 1 +#define GEN_MAGIC_THROW 2 + +static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, + int *pdone, int magic) +{ + JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR); + JSStackFrame *sf; + JSValue ret, func_ret; + + *pdone = true; + if (!s) + return JS_ThrowTypeError(ctx, "not a generator"); + sf = &s->func_state.frame; + switch(s->state) { + default: + case JS_GENERATOR_STATE_SUSPENDED_START: + if (magic == GEN_MAGIC_NEXT) { + goto exec_no_arg; + } else { + free_generator_stack(ctx, s); + goto done; + } + break; + case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR: + case JS_GENERATOR_STATE_SUSPENDED_YIELD: + /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */ + ret = js_dup(argv[0]); + if (magic == GEN_MAGIC_THROW && + s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) { + JS_Throw(ctx, ret); + s->func_state.throw_flag = true; + } else { + sf->cur_sp[-1] = ret; + sf->cur_sp[0] = js_int32(magic); + sf->cur_sp++; + exec_no_arg: + s->func_state.throw_flag = false; + } + s->state = JS_GENERATOR_STATE_EXECUTING; + func_ret = async_func_resume(ctx, &s->func_state); + s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD; + if (JS_IsException(func_ret)) { + /* finalize the execution in case of exception */ + free_generator_stack(ctx, s); + return func_ret; + } + if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) { + /* get the returned yield value at the top of the stack */ + ret = sf->cur_sp[-1]; + sf->cur_sp[-1] = JS_UNDEFINED; + if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) { + s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR; + /* return (value, done) object */ + *pdone = 2; + } else { + *pdone = false; + } + } else { + /* end of iterator */ + ret = sf->cur_sp[-1]; + sf->cur_sp[-1] = JS_UNDEFINED; + JS_FreeValue(ctx, func_ret); + free_generator_stack(ctx, s); + } + break; + case JS_GENERATOR_STATE_COMPLETED: + done: + /* execution is finished */ + switch(magic) { + default: + case GEN_MAGIC_NEXT: + ret = JS_UNDEFINED; + break; + case GEN_MAGIC_RETURN: + ret = js_dup(argv[0]); + break; + case GEN_MAGIC_THROW: + ret = JS_Throw(ctx, js_dup(argv[0])); + break; + } + break; + case JS_GENERATOR_STATE_EXECUTING: + ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator"); + break; + } + return ret; +} + +static JSValue js_call_generator_function(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv, + int flags) +{ + JSValue obj, func_ret; + JSGeneratorData *s; + + s = js_mallocz(ctx, sizeof(*s)); + if (!s) + return JS_EXCEPTION; + s->state = JS_GENERATOR_STATE_SUSPENDED_START; + if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { + s->state = JS_GENERATOR_STATE_COMPLETED; + goto fail; + } + + /* execute the function up to 'OP_initial_yield' */ + func_ret = async_func_resume(ctx, &s->func_state); + if (JS_IsException(func_ret)) + goto fail; + JS_FreeValue(ctx, func_ret); + + obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR); + if (JS_IsException(obj)) + goto fail; + JS_SetOpaqueInternal(obj, s); + return obj; + fail: + free_generator_stack_rt(ctx->rt, s); + js_free(ctx, s); + return JS_EXCEPTION; +} + +/* AsyncFunction */ + +static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s) +{ + if (s->is_active) { + async_func_free(rt, &s->func_state); + s->is_active = false; + } +} + +static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s) +{ + js_async_function_terminate(rt, s); + JS_FreeValueRT(rt, s->resolving_funcs[0]); + JS_FreeValueRT(rt, s->resolving_funcs[1]); + remove_gc_object(&s->header); + js_free_rt(rt, s); +} + +static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s) +{ + if (--s->header.ref_count == 0) { + js_async_function_free0(rt, s); + } +} + +static void js_async_function_resolve_finalizer(JSRuntime *rt, + JSValueConst val) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSAsyncFunctionData *s = p->u.async_function_data; + if (s) { + js_async_function_free(rt, s); + } +} + +static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSAsyncFunctionData *s = p->u.async_function_data; + if (s) { + mark_func(rt, &s->header); + } +} + +static int js_async_function_resolve_create(JSContext *ctx, + JSAsyncFunctionData *s, + JSValue *resolving_funcs) +{ + int i; + JSObject *p; + + for(i = 0; i < 2; i++) { + resolving_funcs[i] = + JS_NewObjectProtoClass(ctx, ctx->function_proto, + JS_CLASS_ASYNC_FUNCTION_RESOLVE + i); + if (JS_IsException(resolving_funcs[i])) { + if (i == 1) + JS_FreeValue(ctx, resolving_funcs[0]); + return -1; + } + p = JS_VALUE_GET_OBJ(resolving_funcs[i]); + s->header.ref_count++; + p->u.async_function_data = s; + } + return 0; +} + +static bool js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s) +{ + bool is_success = true; + JSValue func_ret, ret2; + + func_ret = async_func_resume(ctx, &s->func_state); + if (JS_IsException(func_ret)) { + fail: + if (unlikely(JS_IsUncatchableError(ctx->rt->current_exception))) { + is_success = false; + } else { + JSValue error = JS_GetException(ctx); + ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED, + 1, vc(&error)); + JS_FreeValue(ctx, error); + resolved: + if (unlikely(JS_IsException(ret2))) { + if (JS_IsUncatchableError(ctx->rt->current_exception)) { + is_success = false; + } else { + abort(); /* BUG */ + } + } + JS_FreeValue(ctx, ret2); + } + js_async_function_terminate(ctx->rt, s); + } else { + JSValue value; + value = s->func_state.frame.cur_sp[-1]; + s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; + if (JS_IsUndefined(func_ret)) { + /* function returned */ + ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED, + 1, vc(&value)); + JS_FreeValue(ctx, value); + goto resolved; + } else { + JSValue promise, resolving_funcs[2], resolving_funcs1[2]; + int i, res; + + /* await */ + JS_FreeValue(ctx, func_ret); /* not used */ + promise = js_promise_resolve(ctx, ctx->promise_ctor, + 1, vc(&value), 0); + JS_FreeValue(ctx, value); + if (JS_IsException(promise)) + goto fail; + if (js_async_function_resolve_create(ctx, s, resolving_funcs)) { + JS_FreeValue(ctx, promise); + goto fail; + } + + /* Note: no need to create 'thrownawayCapability' as in + the spec */ + for(i = 0; i < 2; i++) + resolving_funcs1[i] = JS_UNDEFINED; + res = perform_promise_then(ctx, promise, + vc(resolving_funcs), + vc(resolving_funcs1)); + JS_FreeValue(ctx, promise); + for(i = 0; i < 2; i++) + JS_FreeValue(ctx, resolving_funcs[i]); + if (res) + goto fail; + } + } + return is_success; +} + +static JSValue js_async_function_resolve_call(JSContext *ctx, + JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv, + int flags) +{ + JSObject *p = JS_VALUE_GET_OBJ(func_obj); + JSAsyncFunctionData *s = p->u.async_function_data; + bool is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE; + JSValueConst arg; + + if (argc > 0) + arg = argv[0]; + else + arg = JS_UNDEFINED; + s->func_state.throw_flag = is_reject; + if (is_reject) { + JS_Throw(ctx, js_dup(arg)); + } else { + /* return value of await */ + s->func_state.frame.cur_sp[-1] = js_dup(arg); + } + if (!js_async_function_resume(ctx, s)) + return JS_EXCEPTION; + return JS_UNDEFINED; +} + +static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv, int flags) +{ + JSValue promise; + JSAsyncFunctionData *s; + + s = js_mallocz(ctx, sizeof(*s)); + if (!s) + return JS_EXCEPTION; + s->header.ref_count = 1; + add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION); + s->is_active = false; + s->resolving_funcs[0] = JS_UNDEFINED; + s->resolving_funcs[1] = JS_UNDEFINED; + + promise = JS_NewPromiseCapability(ctx, s->resolving_funcs); + if (JS_IsException(promise)) + goto fail; + + if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { + fail: + JS_FreeValue(ctx, promise); + js_async_function_free(ctx->rt, s); + return JS_EXCEPTION; + } + s->is_active = true; + + if (!js_async_function_resume(ctx, s)) + goto fail; + + js_async_function_free(ctx->rt, s); + + return promise; +} + +/* AsyncGenerator */ + +typedef enum JSAsyncGeneratorStateEnum { + JS_ASYNC_GENERATOR_STATE_SUSPENDED_START, + JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD, + JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR, + JS_ASYNC_GENERATOR_STATE_EXECUTING, + JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN, + JS_ASYNC_GENERATOR_STATE_COMPLETED, +} JSAsyncGeneratorStateEnum; + +typedef struct JSAsyncGeneratorRequest { + struct list_head link; + /* completion */ + int completion_type; /* GEN_MAGIC_x */ + JSValue result; + /* promise capability */ + JSValue promise; + JSValue resolving_funcs[2]; +} JSAsyncGeneratorRequest; + +typedef struct JSAsyncGeneratorData { + JSObject *generator; /* back pointer to the object (const) */ + JSAsyncGeneratorStateEnum state; + JSAsyncFunctionState func_state; + struct list_head queue; /* list of JSAsyncGeneratorRequest.link */ +} JSAsyncGeneratorData; + +static void js_async_generator_free(JSRuntime *rt, + JSAsyncGeneratorData *s) +{ + struct list_head *el, *el1; + JSAsyncGeneratorRequest *req; + + list_for_each_safe(el, el1, &s->queue) { + req = list_entry(el, JSAsyncGeneratorRequest, link); + JS_FreeValueRT(rt, req->result); + JS_FreeValueRT(rt, req->promise); + JS_FreeValueRT(rt, req->resolving_funcs[0]); + JS_FreeValueRT(rt, req->resolving_funcs[1]); + js_free_rt(rt, req); + } + if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED && + s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) { + async_func_free(rt, &s->func_state); + } + js_free_rt(rt, s); +} + +static void js_async_generator_finalizer(JSRuntime *rt, JSValueConst obj) +{ + JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR); + + if (s) { + js_async_generator_free(rt, s); + } +} + +static void js_async_generator_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR); + struct list_head *el; + JSAsyncGeneratorRequest *req; + if (s) { + list_for_each(el, &s->queue) { + req = list_entry(el, JSAsyncGeneratorRequest, link); + JS_MarkValue(rt, req->result, mark_func); + JS_MarkValue(rt, req->promise, mark_func); + JS_MarkValue(rt, req->resolving_funcs[0], mark_func); + JS_MarkValue(rt, req->resolving_funcs[1], mark_func); + } + if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED && + s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) { + async_func_mark(rt, &s->func_state, mark_func); + } + } +} + +static JSValue js_async_generator_resolve_function(JSContext *ctx, + JSValueConst this_obj, + int argc, JSValueConst *argv, + int magic, JSValueConst *func_data); + +static int js_async_generator_resolve_function_create(JSContext *ctx, + JSValue generator, + JSValue *resolving_funcs, + bool is_resume_next) +{ + int i; + JSValue func; + + for(i = 0; i < 2; i++) { + func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1, + i + is_resume_next * 2, 1, vc(&generator)); + if (JS_IsException(func)) { + if (i == 1) + JS_FreeValue(ctx, resolving_funcs[0]); + return -1; + } + resolving_funcs[i] = func; + } + return 0; +} + +static int js_async_generator_await(JSContext *ctx, + JSAsyncGeneratorData *s, + JSValue value) +{ + JSValue promise, resolving_funcs[2], resolving_funcs1[2]; + int i, res; + + promise = js_promise_resolve(ctx, ctx->promise_ctor, + 1, vc(&value), 0); + if (JS_IsException(promise)) + goto fail; + + if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator), + resolving_funcs, false)) { + JS_FreeValue(ctx, promise); + goto fail; + } + + /* Note: no need to create 'thrownawayCapability' as in + the spec */ + for(i = 0; i < 2; i++) + resolving_funcs1[i] = JS_UNDEFINED; + res = perform_promise_then(ctx, promise, + vc(resolving_funcs), + vc(resolving_funcs1)); + JS_FreeValue(ctx, promise); + for(i = 0; i < 2; i++) + JS_FreeValue(ctx, resolving_funcs[i]); + if (res) + goto fail; + return 0; + fail: + return -1; +} + +static void js_async_generator_resolve_or_reject(JSContext *ctx, + JSAsyncGeneratorData *s, + JSValueConst result, + int is_reject) +{ + JSAsyncGeneratorRequest *next; + JSValue ret; + + next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link); + list_del(&next->link); + ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1, + &result); + JS_FreeValue(ctx, ret); + JS_FreeValue(ctx, next->result); + JS_FreeValue(ctx, next->promise); + JS_FreeValue(ctx, next->resolving_funcs[0]); + JS_FreeValue(ctx, next->resolving_funcs[1]); + js_free(ctx, next); +} + +static void js_async_generator_resolve(JSContext *ctx, + JSAsyncGeneratorData *s, + JSValueConst value, + bool done) +{ + JSValue result; + result = js_create_iterator_result(ctx, js_dup(value), done); + /* XXX: better exception handling ? */ + js_async_generator_resolve_or_reject(ctx, s, result, 0); + JS_FreeValue(ctx, result); + } + +static void js_async_generator_reject(JSContext *ctx, + JSAsyncGeneratorData *s, + JSValueConst exception) +{ + js_async_generator_resolve_or_reject(ctx, s, exception, 1); +} + +static void js_async_generator_complete(JSContext *ctx, + JSAsyncGeneratorData *s) +{ + if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) { + s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; + async_func_free(ctx->rt, &s->func_state); + } +} + +static int js_async_generator_completed_return(JSContext *ctx, + JSAsyncGeneratorData *s, + JSValue value) +{ + JSValue promise, resolving_funcs[2], resolving_funcs1[2]; + int res; + + // Can fail looking up JS_ATOM_constructor when is_reject==0. + promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&value), + /*is_reject*/0); + // A poisoned .constructor property is observable and the resulting + // exception should be delivered to the catch handler. + if (JS_IsException(promise)) { + JSValue err = JS_GetException(ctx); + promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&err), + /*is_reject*/1); + JS_FreeValue(ctx, err); + if (JS_IsException(promise)) + return -1; + } + if (js_async_generator_resolve_function_create(ctx, + JS_MKPTR(JS_TAG_OBJECT, s->generator), + resolving_funcs1, + true)) { + JS_FreeValue(ctx, promise); + return -1; + } + resolving_funcs[0] = JS_UNDEFINED; + resolving_funcs[1] = JS_UNDEFINED; + res = perform_promise_then(ctx, promise, + vc(resolving_funcs1), + vc(resolving_funcs)); + JS_FreeValue(ctx, resolving_funcs1[0]); + JS_FreeValue(ctx, resolving_funcs1[1]); + JS_FreeValue(ctx, promise); + return res; +} + +static void js_async_generator_resume_next(JSContext *ctx, + JSAsyncGeneratorData *s) +{ + JSAsyncGeneratorRequest *next; + JSValue func_ret, value; + + for(;;) { + if (list_empty(&s->queue)) + break; + next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link); + switch(s->state) { + case JS_ASYNC_GENERATOR_STATE_EXECUTING: + /* only happens when restarting execution after await() */ + goto resume_exec; + case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN: + goto done; + case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START: + if (next->completion_type == GEN_MAGIC_NEXT) { + goto exec_no_arg; + } else { + js_async_generator_complete(ctx, s); + } + break; + case JS_ASYNC_GENERATOR_STATE_COMPLETED: + if (next->completion_type == GEN_MAGIC_NEXT) { + js_async_generator_resolve(ctx, s, JS_UNDEFINED, true); + } else if (next->completion_type == GEN_MAGIC_RETURN) { + s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN; + js_async_generator_completed_return(ctx, s, next->result); + } else { + js_async_generator_reject(ctx, s, next->result); + } + goto done; + case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD: + case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR: + value = js_dup(next->result); + if (next->completion_type == GEN_MAGIC_THROW && + s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) { + JS_Throw(ctx, value); + s->func_state.throw_flag = true; + } else { + /* 'yield' returns a value. 'yield *' also returns a value + in case the 'throw' method is called */ + s->func_state.frame.cur_sp[-1] = value; + s->func_state.frame.cur_sp[0] = + js_int32(next->completion_type); + s->func_state.frame.cur_sp++; + exec_no_arg: + s->func_state.throw_flag = false; + } + s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING; + resume_exec: + func_ret = async_func_resume(ctx, &s->func_state); + if (JS_IsException(func_ret)) { + value = JS_GetException(ctx); + js_async_generator_complete(ctx, s); + js_async_generator_reject(ctx, s, value); + JS_FreeValue(ctx, value); + } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) { + int func_ret_code, ret; + value = s->func_state.frame.cur_sp[-1]; + s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; + func_ret_code = JS_VALUE_GET_INT(func_ret); + switch(func_ret_code) { + case FUNC_RET_YIELD: + case FUNC_RET_YIELD_STAR: + if (func_ret_code == FUNC_RET_YIELD_STAR) + s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR; + else + s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD; + js_async_generator_resolve(ctx, s, value, false); + JS_FreeValue(ctx, value); + break; + case FUNC_RET_AWAIT: + ret = js_async_generator_await(ctx, s, value); + JS_FreeValue(ctx, value); + if (ret < 0) { + /* exception: throw it */ + s->func_state.throw_flag = true; + goto resume_exec; + } + goto done; + default: + abort(); + } + } else { + assert(JS_IsUndefined(func_ret)); + /* end of function */ + value = s->func_state.frame.cur_sp[-1]; + s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; + js_async_generator_complete(ctx, s); + js_async_generator_resolve(ctx, s, value, true); + JS_FreeValue(ctx, value); + } + break; + default: + abort(); + } + } + done: ; +} + +static JSValue js_async_generator_resolve_function(JSContext *ctx, + JSValueConst this_obj, + int argc, JSValueConst *argv, + int magic, JSValueConst *func_data) +{ + bool is_reject = magic & 1; + JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR); + JSValueConst arg = argv[0]; + + /* XXX: what if s == NULL */ + + if (magic >= 2) { + /* resume next case in AWAITING_RETURN state */ + assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN || + s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED); + s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; + if (is_reject) { + js_async_generator_reject(ctx, s, arg); + } else { + js_async_generator_resolve(ctx, s, arg, true); + } + } else { + /* restart function execution after await() */ + assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING); + s->func_state.throw_flag = is_reject; + if (is_reject) { + JS_Throw(ctx, js_dup(arg)); + } else { + /* return value of await */ + s->func_state.frame.cur_sp[-1] = js_dup(arg); + } + js_async_generator_resume_next(ctx, s); + } + return JS_UNDEFINED; +} + +/* magic = GEN_MAGIC_x */ +static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, + int magic) +{ + JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR); + JSValue promise, resolving_funcs[2]; + JSAsyncGeneratorRequest *req; + + promise = JS_NewPromiseCapability(ctx, resolving_funcs); + if (JS_IsException(promise)) + return JS_EXCEPTION; + if (!s) { + JSValue err, res2; + JS_ThrowTypeError(ctx, "not an AsyncGenerator object"); + err = JS_GetException(ctx); + res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, + 1, vc(&err)); + JS_FreeValue(ctx, err); + JS_FreeValue(ctx, res2); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return promise; + } + req = js_mallocz(ctx, sizeof(*req)); + if (!req) + goto fail; + req->completion_type = magic; + req->result = js_dup(argv[0]); + req->promise = js_dup(promise); + req->resolving_funcs[0] = resolving_funcs[0]; + req->resolving_funcs[1] = resolving_funcs[1]; + list_add_tail(&req->link, &s->queue); + if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) { + js_async_generator_resume_next(ctx, s); + } + return promise; + fail: + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + JS_FreeValue(ctx, promise); + return JS_EXCEPTION; +} + +static JSValue js_async_generator_function_call(JSContext *ctx, + JSValueConst func_obj, + JSValueConst this_obj, + int argc, JSValueConst *argv, + int flags) +{ + JSValue obj, func_ret; + JSAsyncGeneratorData *s; + + s = js_mallocz(ctx, sizeof(*s)); + if (!s) + return JS_EXCEPTION; + s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START; + init_list_head(&s->queue); + if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { + s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; + goto fail; + } + + /* execute the function up to 'OP_initial_yield' (no yield nor + await are possible) */ + func_ret = async_func_resume(ctx, &s->func_state); + if (JS_IsException(func_ret)) + goto fail; + JS_FreeValue(ctx, func_ret); + + obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR); + if (JS_IsException(obj)) + goto fail; + s->generator = JS_VALUE_GET_OBJ(obj); + JS_SetOpaqueInternal(obj, s); + return obj; + fail: + js_async_generator_free(ctx->rt, s); + return JS_EXCEPTION; +} + +/* JS parser */ + +enum { + TOK_NUMBER = -128, + TOK_STRING, + TOK_TEMPLATE, + TOK_IDENT, + TOK_REGEXP, + /* warning: order matters (see js_parse_assign_expr) */ + TOK_MUL_ASSIGN, + TOK_DIV_ASSIGN, + TOK_MOD_ASSIGN, + TOK_PLUS_ASSIGN, + TOK_MINUS_ASSIGN, + TOK_SHL_ASSIGN, + TOK_SAR_ASSIGN, + TOK_SHR_ASSIGN, + TOK_AND_ASSIGN, + TOK_XOR_ASSIGN, + TOK_OR_ASSIGN, + TOK_POW_ASSIGN, + TOK_LAND_ASSIGN, + TOK_LOR_ASSIGN, + TOK_DOUBLE_QUESTION_MARK_ASSIGN, + TOK_DEC, + TOK_INC, + TOK_SHL, + TOK_SAR, + TOK_SHR, + TOK_LT, + TOK_LTE, + TOK_GT, + TOK_GTE, + TOK_EQ, + TOK_STRICT_EQ, + TOK_NEQ, + TOK_STRICT_NEQ, + TOK_LAND, + TOK_LOR, + TOK_POW, + TOK_ARROW, + TOK_ELLIPSIS, + TOK_DOUBLE_QUESTION_MARK, + TOK_QUESTION_MARK_DOT, + TOK_ERROR, + TOK_PRIVATE_NAME, + TOK_EOF, + /* keywords: WARNING: same order as atoms */ + TOK_NULL, /* must be first */ + TOK_FALSE, + TOK_TRUE, + TOK_IF, + TOK_ELSE, + TOK_RETURN, + TOK_VAR, + TOK_THIS, + TOK_DELETE, + TOK_VOID, + TOK_TYPEOF, + TOK_NEW, + TOK_IN, + TOK_INSTANCEOF, + TOK_DO, + TOK_WHILE, + TOK_FOR, + TOK_BREAK, + TOK_CONTINUE, + TOK_SWITCH, + TOK_CASE, + TOK_DEFAULT, + TOK_THROW, + TOK_TRY, + TOK_CATCH, + TOK_FINALLY, + TOK_FUNCTION, + TOK_DEBUGGER, + TOK_WITH, + /* FutureReservedWord */ + TOK_CLASS, + TOK_CONST, + TOK_ENUM, + TOK_EXPORT, + TOK_EXTENDS, + TOK_IMPORT, + TOK_SUPER, + /* FutureReservedWords when parsing strict mode code */ + TOK_IMPLEMENTS, + TOK_INTERFACE, + TOK_LET, + TOK_PACKAGE, + TOK_PRIVATE, + TOK_PROTECTED, + TOK_PUBLIC, + TOK_STATIC, + TOK_YIELD, + TOK_AWAIT, /* must be last */ + TOK_OF, /* only used for js_parse_skip_parens_token() */ +}; + +#define TOK_FIRST_KEYWORD TOK_NULL +#define TOK_LAST_KEYWORD TOK_AWAIT + +/* unicode code points */ +#define CP_NBSP 0x00a0 +#define CP_BOM 0xfeff + +#define CP_LS 0x2028 +#define CP_PS 0x2029 + +typedef struct BlockEnv { + struct BlockEnv *prev; + JSAtom label_name; /* JS_ATOM_NULL if none */ + int label_break; /* -1 if none */ + int label_cont; /* -1 if none */ + int drop_count; /* number of stack elements to drop */ + int label_finally; /* -1 if none */ + int scope_level; + uint8_t has_iterator : 1; + uint8_t is_regular_stmt : 1; // i.e. not a loop statement +} BlockEnv; + +typedef struct JSGlobalVar { + int cpool_idx; /* if >= 0, index in the constant pool for hoisted + function defintion*/ + uint8_t force_init : 1; /* force initialization to undefined */ + uint8_t is_lexical : 1; /* global let/const definition */ + uint8_t is_const : 1; /* const definition */ + int scope_level; /* scope of definition */ + JSAtom var_name; /* variable name */ +} JSGlobalVar; + +typedef struct RelocEntry { + struct RelocEntry *next; + uint32_t addr; /* address to patch */ + int size; /* address size: 1, 2 or 4 bytes */ +} RelocEntry; + +typedef struct JumpSlot { + int op; + int size; + int pos; + int label; +} JumpSlot; + +typedef struct LabelSlot { + int ref_count; + int pos; /* phase 1 address, -1 means not resolved yet */ + int pos2; /* phase 2 address, -1 means not resolved yet */ + int addr; /* phase 3 address, -1 means not resolved yet */ + RelocEntry *first_reloc; +} LabelSlot; + +typedef struct SourceLocSlot { + uint32_t pc; + int line_num; + int col_num; +} SourceLocSlot; + +typedef enum JSParseFunctionEnum { + JS_PARSE_FUNC_STATEMENT, + JS_PARSE_FUNC_VAR, + JS_PARSE_FUNC_EXPR, + JS_PARSE_FUNC_ARROW, + JS_PARSE_FUNC_GETTER, + JS_PARSE_FUNC_SETTER, + JS_PARSE_FUNC_METHOD, + JS_PARSE_FUNC_CLASS_STATIC_INIT, + JS_PARSE_FUNC_CLASS_CONSTRUCTOR, + JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR, +} JSParseFunctionEnum; + +typedef enum JSParseExportEnum { + JS_PARSE_EXPORT_NONE, + JS_PARSE_EXPORT_NAMED, + JS_PARSE_EXPORT_DEFAULT, +} JSParseExportEnum; + +typedef struct JSFunctionDef { + JSContext *ctx; + struct JSFunctionDef *parent; + int parent_cpool_idx; /* index in the constant pool of the parent + or -1 if none */ + int parent_scope_level; /* scope level in parent at point of definition */ + struct list_head child_list; /* list of JSFunctionDef.link */ + struct list_head link; + + int eval_type; /* only valid if is_eval = true */ + + /* Pack all boolean flags together as 1-bit fields to reduce struct size + while avoiding padding and compiler deoptimization. */ + bool is_eval : 1; /* true if eval code */ + bool is_global_var : 1; /* true if variables are not defined locally: + eval global, eval module or non strict eval */ + bool is_func_expr : 1; /* true if function expression */ + bool has_home_object : 1; /* true if the home object is available */ + bool has_prototype : 1; /* true if a prototype field is necessary */ + bool has_simple_parameter_list : 1; + bool has_parameter_expressions : 1; /* if true, an argument scope is created */ + bool has_use_strict : 1; /* to reject directive in special cases */ + bool has_eval_call : 1; /* true if the function contains a call to eval() */ + bool has_arguments_binding : 1; /* true if the 'arguments' binding is + available in the function */ + bool has_this_binding : 1; /* true if the 'this' and new.target binding are + available in the function */ + bool new_target_allowed : 1; /* true if the 'new.target' does not + throw a syntax error */ + bool super_call_allowed : 1; /* true if super() is allowed */ + bool super_allowed : 1; /* true if super. or super[] is allowed */ + bool arguments_allowed : 1; /* true if the 'arguments' identifier is allowed */ + bool is_derived_class_constructor : 1; + bool in_function_body : 1; + bool backtrace_barrier : 1; + bool need_home_object : 1; + bool use_short_opcodes : 1; /* true if short opcodes are used in byte_code */ + bool has_await : 1; /* true if await is used (used in module eval) */ + + JSFunctionKindEnum func_kind : 8; + JSParseFunctionEnum func_type : 7; + uint8_t is_strict_mode : 1; + JSAtom func_name; /* JS_ATOM_NULL if no name */ + + JSVarDef *vars; + uint32_t *vars_htab; // indexes into vars[] + int var_size; /* allocated size for vars[] */ + int var_count; + JSVarDef *args; + int arg_size; /* allocated size for args[] */ + int arg_count; /* number of arguments */ + int defined_arg_count; + int var_object_idx; /* -1 if none */ + int arg_var_object_idx; /* -1 if none (var object for the argument scope) */ + int arguments_var_idx; /* -1 if none */ + int arguments_arg_idx; /* argument variable definition in argument scope, + -1 if none */ + int func_var_idx; /* variable containing the current function (-1 + if none, only used if is_func_expr is true) */ + int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */ + int this_var_idx; /* variable containg the 'this' value, -1 if none */ + int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */ + int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */ + int home_object_var_idx; + + int scope_level; /* index into fd->scopes if the current lexical scope */ + int scope_first; /* index into vd->vars of first lexically scoped variable */ + int scope_size; /* allocated size of fd->scopes array */ + int scope_count; /* number of entries used in the fd->scopes array */ + JSVarScope *scopes; + JSVarScope def_scope_array[4]; + int body_scope; /* scope of the body of the function or eval */ + + int global_var_count; + int global_var_size; + JSGlobalVar *global_vars; + + DynBuf byte_code; + int last_opcode_pos; /* -1 if no last opcode */ + + LabelSlot *label_slots; + int label_size; /* allocated size for label_slots[] */ + int label_count; + BlockEnv *top_break; /* break/continue label stack */ + + /* constant pool (strings, functions, numbers) */ + JSValue *cpool; + int cpool_count; + int cpool_size; + + /* list of variables in the closure */ + int closure_var_count; + int closure_var_size; + JSClosureVar *closure_var; + + JumpSlot *jump_slots; + int jump_size; + int jump_count; + + SourceLocSlot *source_loc_slots; + int source_loc_size; + int source_loc_count; + int line_number_last; + int line_number_last_pc; + int col_number_last; + + /* pc2line table */ + JSAtom filename; + int line_num; + int col_num; + DynBuf pc2line; + + char *source; /* raw source, utf-8 encoded */ + int source_len; + + JSModuleDef *module; /* != NULL when parsing a module */ +} JSFunctionDef; + +typedef struct JSToken { + int val; + int line_num; /* line number of token start */ + int col_num; /* column number of token start */ + const uint8_t *ptr; + union { + struct { + JSValue str; + int sep; + } str; + struct { + JSValue val; + } num; + struct { + JSAtom atom; + bool has_escape; + bool is_reserved; + } ident; + struct { + JSValue body; + JSValue flags; + } regexp; + } u; +} JSToken; + +typedef struct JSParseState { + JSContext *ctx; + int last_line_num; /* line number of last token */ + int last_col_num; /* column number of last token */ + int line_num; /* line number of current offset */ + int col_num; /* column number of current offset */ + const char *filename; + JSToken token; + bool got_lf; /* true if got line feed before the current token */ + const uint8_t *last_ptr; + const uint8_t *buf_start; + const uint8_t *buf_ptr; + const uint8_t *buf_end; + const uint8_t *eol; // most recently seen end-of-line character + const uint8_t *mark; // first token character, invariant: eol < mark + + /* current function code */ + JSFunctionDef *cur_func; + bool is_module; /* parsing a module */ + bool allow_html_comments; +} JSParseState; + +typedef struct JSOpCode { +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_* + const char *name; +#endif + uint8_t size; /* in bytes */ + /* the opcodes remove n_pop items from the top of the stack, then + pushes n_push items */ + uint8_t n_pop; + uint8_t n_push; + uint8_t fmt; +} JSOpCode; + +static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = { +#define FMT(f) +#ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_* +#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f }, +#else +#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f }, +#endif +#include "quickjs-opcode.h" +#undef DEF +#undef FMT +}; + +/* After the final compilation pass, short opcodes are used. Their + opcodes overlap with the temporary opcodes which cannot appear in + the final bytecode. Their description is after the temporary + opcodes in opcode_info[]. */ +#define short_opcode_info(op) \ + opcode_info[(op) >= OP_TEMP_START ? \ + (op) + (OP_TEMP_END - OP_TEMP_START) : (op)] + +static void free_token(JSParseState *s, JSToken *token) +{ + switch(token->val) { + case TOK_NUMBER: + JS_FreeValue(s->ctx, token->u.num.val); + break; + case TOK_STRING: + case TOK_TEMPLATE: + JS_FreeValue(s->ctx, token->u.str.str); + break; + case TOK_REGEXP: + JS_FreeValue(s->ctx, token->u.regexp.body); + JS_FreeValue(s->ctx, token->u.regexp.flags); + break; + case TOK_IDENT: + case TOK_PRIVATE_NAME: + JS_FreeAtom(s->ctx, token->u.ident.atom); + break; + default: + if (token->val >= TOK_FIRST_KEYWORD && + token->val <= TOK_LAST_KEYWORD) { + JS_FreeAtom(s->ctx, token->u.ident.atom); + } + break; + } +} + +static void __attribute((unused)) dump_token(JSParseState *s, + const JSToken *token) +{ + printf("%d:%d ", token->line_num, token->col_num); + switch(token->val) { + case TOK_NUMBER: + { + double d; + JS_ToFloat64(s->ctx, &d, token->u.num.val); /* no exception possible */ + printf("number: %.14g\n", d); + } + break; + case TOK_IDENT: + dump_atom: + { + char buf[ATOM_GET_STR_BUF_SIZE]; + printf("ident: '%s'\n", + JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom)); + } + break; + case TOK_STRING: + { + const char *str; + /* XXX: quote the string */ + str = JS_ToCString(s->ctx, token->u.str.str); + printf("string: '%s'\n", str); + JS_FreeCString(s->ctx, str); + } + break; + case TOK_TEMPLATE: + { + const char *str; + str = JS_ToCString(s->ctx, token->u.str.str); + printf("template: `%s`\n", str); + JS_FreeCString(s->ctx, str); + } + break; + case TOK_REGEXP: + { + const char *str, *str2; + str = JS_ToCString(s->ctx, token->u.regexp.body); + str2 = JS_ToCString(s->ctx, token->u.regexp.flags); + printf("regexp: '%s' '%s'\n", str, str2); + JS_FreeCString(s->ctx, str); + JS_FreeCString(s->ctx, str2); + } + break; + case TOK_EOF: + printf("eof\n"); + break; + default: + if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) { + goto dump_atom; + } else if (s->token.val >= 256) { + printf("token: %d\n", token->val); + } else { + printf("token: '%c'\n", token->val); + } + break; + } +} + +int JS_PRINTF_FORMAT_ATTR(2, 3) js_parse_error(JSParseState *s, JS_PRINTF_FORMAT const char *fmt, ...) +{ + JSContext *ctx = s->ctx; + va_list ap; + int backtrace_flags; + + va_start(ap, fmt); + JS_ThrowError2(ctx, JS_SYNTAX_ERROR, false, fmt, ap); + va_end(ap); + backtrace_flags = 0; + if (s->cur_func && s->cur_func->backtrace_barrier) + backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL; + build_backtrace(ctx, ctx->rt->current_exception, JS_UNDEFINED, s->filename, + s->line_num, s->col_num, backtrace_flags); + return -1; +} + +#ifndef QJS_DISABLE_PARSER + +static __exception int next_token(JSParseState *s); + +static int js_parse_expect(JSParseState *s, int tok) +{ + char buf[ATOM_GET_STR_BUF_SIZE]; + + if (s->token.val == tok) + return next_token(s); + + switch(s->token.val) { + case TOK_EOF: + return js_parse_error(s, "Unexpected end of input"); + case TOK_NUMBER: + return js_parse_error(s, "Unexpected number"); + case TOK_STRING: + return js_parse_error(s, "Unexpected string"); + case TOK_TEMPLATE: + return js_parse_error(s, "Unexpected string template"); + case TOK_REGEXP: + return js_parse_error(s, "Unexpected regexp"); + case TOK_IDENT: + return js_parse_error(s, "Unexpected identifier '%s'", + JS_AtomGetStr(s->ctx, buf, sizeof(buf), + s->token.u.ident.atom)); + case TOK_ERROR: + return js_parse_error(s, "Invalid or unexpected token"); + default: + return js_parse_error(s, "Unexpected token '%.*s'", + (int)(s->buf_ptr - s->token.ptr), + (const char *)s->token.ptr); + } +} + +static int js_parse_expect_semi(JSParseState *s) +{ + if (s->token.val != ';') { + /* automatic insertion of ';' */ + if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) { + return 0; + } + return js_parse_error(s, "expecting '%c'", ';'); + } + return next_token(s); +} + +static int js_parse_error_reserved_identifier(JSParseState *s) +{ + char buf1[ATOM_GET_STR_BUF_SIZE]; + return js_parse_error(s, "'%s' is a reserved identifier", + JS_AtomGetStr(s->ctx, buf1, sizeof(buf1), + s->token.u.ident.atom)); +} + +static __exception int js_parse_template_part(JSParseState *s, + const uint8_t *p) +{ + const uint8_t *p_next; + uint32_t c; + StringBuffer b_s, *b = &b_s; + JSValue str; + + /* p points to the first byte of the template part */ + if (string_buffer_init(s->ctx, b, 32)) + goto fail; + for(;;) { + if (p >= s->buf_end) + goto unexpected_eof; + c = *p++; + if (c == '`') { + /* template end part */ + break; + } + if (c == '$' && *p == '{') { + /* template start or middle part */ + p++; + break; + } + if (c == '\\') { + if (string_buffer_putc8(b, c)) + goto fail; + if (p >= s->buf_end) + goto unexpected_eof; + c = *p++; + } + /* newline sequences are normalized as single '\n' bytes */ + if (c == '\r') { + if (*p == '\n') + p++; + c = '\n'; + } + if (c == '\n') { + s->line_num++; + s->eol = &p[-1]; + s->mark = p; + } else if (c >= 0x80) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) { + js_parse_error(s, "invalid UTF-8 sequence"); + goto fail; + } + p = p_next; + } + if (string_buffer_putc(b, c)) + goto fail; + } + str = string_buffer_end(b); + if (JS_IsException(str)) + return -1; + s->token.val = TOK_TEMPLATE; + s->token.u.str.sep = c; + s->token.u.str.str = str; + s->buf_ptr = p; + return 0; + + unexpected_eof: + js_parse_error(s, "unexpected end of string"); + fail: + string_buffer_free(b); + return -1; +} + +static __exception int js_parse_string(JSParseState *s, int sep, + bool do_throw, const uint8_t *p, + JSToken *token, const uint8_t **pp) +{ + const uint8_t *p_next; + int ret; + uint32_t c; + StringBuffer b_s, *b = &b_s; + JSValue str; + + /* string */ + if (string_buffer_init(s->ctx, b, 32)) + goto fail; + for(;;) { + if (p >= s->buf_end) + goto invalid_char; + c = *p; + if (c < 0x20) { + if (sep == '`') { + if (c == '\r') { + if (p[1] == '\n') + p++; + c = '\n'; + } + /* do not update s->line_num */ + } else if (c == '\n' || c == '\r') + goto invalid_char; + } + p++; + if (c == sep) + break; + if (c == '$' && *p == '{' && sep == '`') { + /* template start or middle part */ + p++; + break; + } + if (c == '\\') { + c = *p; + switch(c) { + case '\0': + if (p >= s->buf_end) { + if (sep != '`') + goto invalid_char; + if (do_throw) + js_parse_error(s, "Unexpected end of input"); + goto fail; + } + p++; + break; + case '\'': + case '\"': + case '\\': + p++; + break; + case '\r': /* accept DOS and MAC newline sequences */ + if (p[1] == '\n') { + p++; + } + /* fall thru */ + case '\n': + /* ignore escaped newline sequence */ + p++; + if (sep != '`') { + s->line_num++; + s->eol = &p[-1]; + s->mark = p; + } + continue; + default: + if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) { + /* accept isolated \0 */ + p++; + c = '\0'; + } else + if ((c >= '0' && c <= '9') + && (s->cur_func->is_strict_mode || sep == '`')) { + if (do_throw) { + js_parse_error(s, "%s are not allowed in %s", + (c >= '8') ? "\\8 and \\9" : "Octal escape sequences", + (sep == '`') ? "template strings" : "strict mode"); + } + goto fail; + } else if (c >= 0x80) { + c = utf8_decode(p, &p_next); + if (p_next == p + 1) { + goto invalid_utf8; + } + p = p_next; + /* LS or PS are skipped */ + if (c == CP_LS || c == CP_PS) + continue; + } else { + ret = lre_parse_escape(&p, true); + if (ret == -1) { + if (do_throw) { + js_parse_error(s, "Invalid %s escape sequence", + c == 'u' ? "Unicode" : "hexadecimal"); + } + goto fail; + } else if (ret < 0) { + /* ignore the '\' (could output a warning) */ + p++; + } else { + c = ret; + } + } + break; + } + } else if (c >= 0x80) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) + goto invalid_utf8; + p = p_next; + } + if (string_buffer_putc(b, c)) + goto fail; + } + str = string_buffer_end(b); + if (JS_IsException(str)) + return -1; + token->val = TOK_STRING; + token->u.str.sep = c; + token->u.str.str = str; + *pp = p; + return 0; + + invalid_utf8: + if (do_throw) + js_parse_error(s, "invalid UTF-8 sequence"); + goto fail; + invalid_char: + if (do_throw) + js_parse_error(s, "unexpected end of string"); + fail: + string_buffer_free(b); + return -1; +} + +static inline bool token_is_pseudo_keyword(JSParseState *s, JSAtom atom) { + return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom && + !s->token.u.ident.has_escape; +} + +static __exception int js_parse_regexp(JSParseState *s) +{ + const uint8_t *p, *p_next; + bool in_class; + StringBuffer b_s, *b = &b_s; + StringBuffer b2_s, *b2 = &b2_s; + uint32_t c; + JSValue body_str, flags_str; + + p = s->buf_ptr; + p++; + in_class = false; + if (string_buffer_init(s->ctx, b, 32)) + return -1; + if (string_buffer_init(s->ctx, b2, 1)) + goto fail; + for(;;) { + if (p >= s->buf_end) { + eof_error: + js_parse_error(s, "unexpected end of regexp"); + goto fail; + } + c = *p++; + if (c == '\n' || c == '\r') { + goto eol_error; + } else if (c == '/') { + if (!in_class) + break; + } else if (c == '[') { + in_class = true; + } else if (c == ']') { + /* XXX: incorrect as the first character in a class */ + in_class = false; + } else if (c == '\\') { + if (string_buffer_putc8(b, c)) + goto fail; + c = *p++; + if (c == '\n' || c == '\r') + goto eol_error; + else if (c == '\0' && p >= s->buf_end) + goto eof_error; + else if (c >= 0x80) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) { + goto invalid_utf8; + } + p = p_next; + if (c == CP_LS || c == CP_PS) + goto eol_error; + } + } else if (c >= 0x80) { + c = utf8_decode(p - 1, &p_next); + if (p_next == p) { + invalid_utf8: + js_parse_error(s, "invalid UTF-8 sequence"); + goto fail; + } + p = p_next; + /* LS or PS are considered as line terminator */ + if (c == CP_LS || c == CP_PS) { + eol_error: + js_parse_error(s, "unexpected line terminator in regexp"); + goto fail; + } + } + if (string_buffer_putc(b, c)) + goto fail; + } + + /* flags */ + for(;;) { + c = utf8_decode(p, &p_next); + /* no need to test for invalid UTF-8, 0xFFFD is not ident_next */ + if (!lre_js_is_ident_next(c)) + break; + if (string_buffer_putc(b2, c)) + goto fail; + p = p_next; + } + + body_str = string_buffer_end(b); + flags_str = string_buffer_end(b2); + if (JS_IsException(body_str) || + JS_IsException(flags_str)) { + JS_FreeValue(s->ctx, body_str); + JS_FreeValue(s->ctx, flags_str); + return -1; + } + s->token.val = TOK_REGEXP; + s->token.u.regexp.body = body_str; + s->token.u.regexp.flags = flags_str; + s->buf_ptr = p; + return 0; + fail: + string_buffer_free(b); + string_buffer_free(b2); + return -1; +} + +#endif // QJS_DISABLE_PARSER + +static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize, + char *static_buf) +{ + char *buf, *new_buf; + size_t size, new_size; + + buf = *pbuf; + size = *psize; + if (size >= (SIZE_MAX / 3) * 2) + new_size = SIZE_MAX; + else + new_size = size + (size >> 1); + if (buf == static_buf) { + new_buf = js_malloc(ctx, new_size); + if (!new_buf) + return -1; + memcpy(new_buf, buf, size); + } else { + new_buf = js_realloc(ctx, buf, new_size); + if (!new_buf) + return -1; + } + *pbuf = new_buf; + *psize = new_size; + return 0; +} + +#ifndef QJS_DISABLE_PARSER + +/* convert a TOK_IDENT to a keyword when needed */ +static void update_token_ident(JSParseState *s) +{ + if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD || + (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD && + s->cur_func->is_strict_mode) || + (s->token.u.ident.atom == JS_ATOM_yield && + ((s->cur_func->func_kind & JS_FUNC_GENERATOR) || + (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && + !s->cur_func->in_function_body && s->cur_func->parent && + (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) || + (s->token.u.ident.atom == JS_ATOM_await && + (s->is_module || + (s->cur_func->func_kind & JS_FUNC_ASYNC) || + s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT || + (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && + !s->cur_func->in_function_body && s->cur_func->parent && + ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) || + s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) { + if (s->token.u.ident.has_escape) { + s->token.u.ident.is_reserved = true; + s->token.val = TOK_IDENT; + } else { + /* The keywords atoms are pre allocated */ + s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD; + } + } +} + +/* if the current token is an identifier or keyword, reparse it + according to the current function type */ +static void reparse_ident_token(JSParseState *s) +{ + if (s->token.val == TOK_IDENT || + (s->token.val >= TOK_FIRST_KEYWORD && + s->token.val <= TOK_LAST_KEYWORD)) { + s->token.val = TOK_IDENT; + s->token.u.ident.is_reserved = false; + update_token_ident(s); + } +} + +/* 'c' is the first character. Return JS_ATOM_NULL in case of error */ +static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, + bool *pident_has_escape, int c, bool is_private) +{ + const uint8_t *p, *p_next; + char ident_buf[128], *buf; + size_t ident_size, ident_pos; + JSAtom atom = JS_ATOM_NULL; + + p = *pp; + buf = ident_buf; + ident_size = sizeof(ident_buf); + ident_pos = 0; + if (is_private) + buf[ident_pos++] = '#'; + for(;;) { + if (c < 0x80) { + buf[ident_pos++] = c; + } else { + ident_pos += utf8_encode((uint8_t*)buf + ident_pos, c); + } + c = *p; + p_next = p + 1; + if (c == '\\' && *p_next == 'u') { + c = lre_parse_escape(&p_next, true); + *pident_has_escape = true; + } else if (c >= 0x80) { + c = utf8_decode(p, &p_next); + /* no need to test for invalid UTF-8, 0xFFFD is not ident_next */ + } + if (!lre_js_is_ident_next(c)) + break; + p = p_next; + if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) { + if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) + goto done; + } + } + /* buf is pure ASCII or UTF-8 encoded */ + atom = JS_NewAtomLen(s->ctx, buf, ident_pos); + done: + if (unlikely(buf != ident_buf)) + js_free(s->ctx, buf); + *pp = p; + return atom; +} + + +static __exception int next_token(JSParseState *s) +{ + const uint8_t *p, *p_next; + int c; + bool ident_has_escape; + JSAtom atom; + + if (js_check_stack_overflow(s->ctx->rt, 1000)) { + JS_ThrowStackOverflow(s->ctx); + return -1; + } + + free_token(s, &s->token); + + p = s->last_ptr = s->buf_ptr; + s->got_lf = false; + s->last_line_num = s->token.line_num; + s->last_col_num = s->token.col_num; + redo: + s->token.line_num = s->line_num; + s->token.col_num = s->col_num; + s->token.ptr = p; + c = *p; + switch(c) { + case 0: + if (p >= s->buf_end) { + s->token.val = TOK_EOF; + } else { + goto def_token; + } + break; + case '`': + if (js_parse_template_part(s, p + 1)) + goto fail; + p = s->buf_ptr; + break; + case '\'': + case '\"': + if (js_parse_string(s, c, true, p + 1, &s->token, &p)) + goto fail; + break; + case '\r': /* accept DOS and MAC newline sequences */ + if (p[1] == '\n') { + p++; + } + /* fall thru */ + case '\n': + p++; + line_terminator: + s->eol = &p[-1]; + s->mark = p; + s->got_lf = true; + s->line_num++; + goto redo; + case '\f': + case '\v': + case ' ': + case '\t': + s->mark = ++p; + goto redo; + case '/': + if (p[1] == '*') { + /* comment */ + p += 2; + for(;;) { + if (*p == '\0' && p >= s->buf_end) { + js_parse_error(s, "unexpected end of comment"); + goto fail; + } + if (p[0] == '*' && p[1] == '/') { + p += 2; + break; + } + if (*p == '\n') { + s->line_num++; + s->got_lf = true; /* considered as LF for ASI */ + s->eol = p++; + s->mark = p; + } else if (*p == '\r') { + s->got_lf = true; /* considered as LF for ASI */ + p++; + } else if (*p >= 0x80) { + c = utf8_decode(p, &p); + /* ignore invalid UTF-8 in comments */ + if (c == CP_LS || c == CP_PS) { + s->got_lf = true; /* considered as LF for ASI */ + } + } else { + p++; + } + } + s->mark = p; + goto redo; + } else if (p[1] == '/') { + /* line comment */ + p += 2; + skip_line_comment: + for(;;) { + if (*p == '\0' && p >= s->buf_end) + break; + if (*p == '\r' || *p == '\n') + break; + if (*p >= 0x80) { + c = utf8_decode(p, &p); + /* ignore invalid UTF-8 in comments */ + /* LS or PS are considered as line terminator */ + if (c == CP_LS || c == CP_PS) { + break; + } + } else { + p++; + } + } + s->mark = p; + goto redo; + } else if (p[1] == '=') { + p += 2; + s->token.val = TOK_DIV_ASSIGN; + } else { + p++; + s->token.val = c; + } + break; + case '\\': + if (p[1] == 'u') { + const uint8_t *p1 = p + 1; + int c1 = lre_parse_escape(&p1, true); + if (c1 >= 0 && lre_js_is_ident_first(c1)) { + c = c1; + p = p1; + ident_has_escape = true; + goto has_ident; + } else { + /* XXX: syntax error? */ + } + } + goto def_token; + case 'a': case 'b': case 'c': case 'd': + case 'e': case 'f': case 'g': case 'h': + case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': + case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': + case 'E': case 'F': case 'G': case 'H': + case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': + case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + case '_': + case '$': + /* identifier */ + s->mark = p; + p++; + ident_has_escape = false; + has_ident: + atom = parse_ident(s, &p, &ident_has_escape, c, false); + if (atom == JS_ATOM_NULL) + goto fail; + s->token.u.ident.atom = atom; + s->token.u.ident.has_escape = ident_has_escape; + s->token.u.ident.is_reserved = false; + s->token.val = TOK_IDENT; + update_token_ident(s); + break; + case '#': + /* private name */ + { + p++; + c = *p; + p_next = p + 1; + if (c == '\\' && *p_next == 'u') { + c = lre_parse_escape(&p_next, true); + } else if (c >= 0x80) { + c = utf8_decode(p, &p_next); + if (p_next == p + 1) + goto invalid_utf8; + } + if (!lre_js_is_ident_first(c)) { + js_parse_error(s, "invalid first character of private name"); + goto fail; + } + p = p_next; + ident_has_escape = false; /* not used */ + atom = parse_ident(s, &p, &ident_has_escape, c, true); + if (atom == JS_ATOM_NULL) + goto fail; + s->token.u.ident.atom = atom; + s->token.val = TOK_PRIVATE_NAME; + } + break; + case '.': + if (p[1] == '.' && p[2] == '.') { + p += 3; + s->token.val = TOK_ELLIPSIS; + break; + } + if (p[1] >= '0' && p[1] <= '9') { + goto parse_number; + } else { + goto def_token; + } + break; + case '0': + /* in strict mode, octal literals are not accepted */ + if (is_digit(p[1]) && (s->cur_func->is_strict_mode)) { + js_parse_error(s, "Octal literals are not allowed in strict mode"); + goto fail; + } + goto parse_number; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': + case '9': + /* number */ + parse_number: + { + JSValue ret; + const uint8_t *p1; + int flags; + flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL | + ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX; + ret = js_atof(s->ctx, (const char *)p, (const char **)&p, 0, + flags); + if (JS_IsException(ret)) + goto fail; + /* reject `10instanceof Number` */ + if (JS_VALUE_IS_NAN(ret) || + lre_js_is_ident_next(utf8_decode(p, &p1))) { + JS_FreeValue(s->ctx, ret); + js_parse_error(s, "invalid number literal"); + goto fail; + } + s->token.val = TOK_NUMBER; + s->token.u.num.val = ret; + } + break; + case '*': + if (p[1] == '=') { + p += 2; + s->token.val = TOK_MUL_ASSIGN; + } else if (p[1] == '*') { + if (p[2] == '=') { + p += 3; + s->token.val = TOK_POW_ASSIGN; + } else { + p += 2; + s->token.val = TOK_POW; + } + } else { + goto def_token; + } + break; + case '%': + if (p[1] == '=') { + p += 2; + s->token.val = TOK_MOD_ASSIGN; + } else { + goto def_token; + } + break; + case '+': + if (p[1] == '=') { + p += 2; + s->token.val = TOK_PLUS_ASSIGN; + } else if (p[1] == '+') { + p += 2; + s->token.val = TOK_INC; + } else { + goto def_token; + } + break; + case '-': + if (p[1] == '=') { + p += 2; + s->token.val = TOK_MINUS_ASSIGN; + } else if (p[1] == '-') { + if (s->allow_html_comments && p[2] == '>' && + (s->got_lf || s->last_ptr == s->buf_start)) { + /* Annex B: `-->` at beginning of line is an html comment end. + It extends to the end of the line. + */ + goto skip_line_comment; + } + p += 2; + s->token.val = TOK_DEC; + } else { + goto def_token; + } + break; + case '<': + if (p[1] == '=') { + p += 2; + s->token.val = TOK_LTE; + } else if (p[1] == '<') { + if (p[2] == '=') { + p += 3; + s->token.val = TOK_SHL_ASSIGN; + } else { + p += 2; + s->token.val = TOK_SHL; + } + } else if (s->allow_html_comments && + p[1] == '!' && p[2] == '-' && p[3] == '-') { + /* Annex B: handle `

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%0Dm?}C%n`^7t@L=n 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≫C}V**7UhI-J%6FB9A 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