pijul nest
guest [sign in]

First working shell (with ocaml code)

pmeunier
May 3, 2025, 11:25 AM
UWQB743KR36X6A6JVNK3VH6KMEFUHOUT6ZS2Y2SWIJR55JSF5WQAC

Dependencies

Change contents

  • file addition: src (d--r------)
    [2.1]
  • file addition: mount.rs (----------)
    [0.15]
    use libc::{MS_BIND, mount, umount};
    use std::ffi::CString;
    use tracing::*;
    #[derive(Debug)]
    pub struct Mount {
    target: Option<CString>,
    }
    impl Mount {
    pub fn bind(source: &str, target: &str) -> Result<Mount, std::io::Error> {
    let target = std::ffi::CString::new(target).unwrap();
    unsafe {
    let err = mount(
    std::ffi::CString::new(source).unwrap().as_ptr(),
    target.as_ptr(),
    std::ptr::null(),
    MS_BIND,
    std::ptr::null(),
    );
    error!("err {:?}", err);
    if err == 0 {
    Ok(Mount {
    target: Some(target),
    })
    } else {
    Err(std::io::Error::last_os_error())
    }
    }
    }
    }
    impl Drop for Mount {
    fn drop(&mut self) {
    if let Some(target) = self.target.take() {
    unsafe {
    // Attention au Chroot!
    trace!("umount");
    let r = umount(target.as_ptr());
    trace!(
    "umount done {:?} {:?} {:?}",
    target,
    r,
    std::io::Error::last_os_error()
    );
    }
    }
    }
    }
  • file addition: main.rs (----------)
    [0.15]
    use libc::*;
    use std::ffi::CString;
    use std::path::Path;
    use std::sync::Arc;
    use tracing::*;
    use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
    use elpe::extract::*;
    use elpe::mount::*;
    use elpe::*;
    pub mod proto {
    tonic::include_proto!("elpe");
    }
    pub struct Elpe {
    deb_client: Arc<elpe::Client>,
    }
    use proto::*;
    #[tonic::async_trait]
    impl proto::elpe_server::Elpe for Elpe {
    async fn derivation(
    &self,
    request: tonic::Request<DerivationRequest>,
    ) -> Result<tonic::Response<DerivationReply>, tonic::Status> {
    debug!("Got a request from {:?}", request.remote_addr());
    // let reply = hello_world::HelloReply {
    // message: format!("Hello {}!", request.into_inner().name),
    // };
    // Ok(Response::new(reply))
    unimplemented!()
    }
    async fn ubuntu_release(
    &self,
    request: tonic::Request<UbuntuReleaseRequest>,
    ) -> Result<tonic::Response<DerivationReply>, tonic::Status> {
    debug!("ubuntu release {:?}", request);
    let r = request.into_inner();
    let h = self.deb_client.in_release(r.release).await.unwrap();
    let arch = match r.arch {
    0 => "amd64",
    1 => "aarch64",
    _ => unreachable!(),
    };
    let p = self
    .deb_client
    .packages(&h, &r.repository, arch)
    .await
    .unwrap();
    Ok(tonic::Response::new(proto::DerivationReply {
    path: vec![p.to_str().unwrap().to_string()],
    error: None,
    }))
    }
    async fn ubuntu_package(
    &self,
    request: tonic::Request<UbuntuPackageRequest>,
    ) -> Result<tonic::Response<DerivationReply>, tonic::Status> {
    debug!("request {:?}", request);
    let r = request.into_inner();
    let index: Result<Vec<_>, _> = r
    .index
    .into_iter()
    .map(|index| deb::Index::open(&index))
    .collect();
    let index = index.unwrap();
    let p = download_extract_deps(&index, &self.deb_client, &r.name)
    .await
    .unwrap();
    info!("path {:?}", p);
    Ok(tonic::Response::new(proto::DerivationReply {
    path: p
    .iter()
    .rev()
    .map(|x| x.to_str().unwrap().to_string())
    .collect(),
    error: None,
    }))
    }
    }
    pub fn child<P: AsRef<Path>>(path: &[P]) {
    let store = Path::new("/home/pe/Projets/frix/store/ailpe/store");
    std::fs::create_dir_all(store).unwrap();
    let vm_store = Path::new("/ailpe/store");
    let mut path_env = "PATH=".to_string();
    let mut ld_env = "LD_LIBRARY_PATH=".to_string();
    let mut mounts = Vec::new();
    for p in path {
    use std::fmt::Write;
    let host = store.join(p.as_ref().file_name().unwrap());
    let guest = vm_store.join(p.as_ref().file_name().unwrap());
    std::fs::create_dir_all(&host).unwrap();
    write!(
    &mut path_env,
    "{}/usr/bin:{}/bin:",
    guest.to_str().unwrap(),
    guest.to_str().unwrap()
    )
    .unwrap();
    write!(
    &mut ld_env,
    "{}/lib64/x86_64-linux-gnu:{}/lib/x86_64-linux-gnu:",
    guest.to_str().unwrap(),
    guest.to_str().unwrap()
    )
    .unwrap();
    mounts.push(Mount::bind(p.as_ref().to_str().unwrap(), host.to_str().unwrap()).unwrap());
    }
    println!("{:?}", mounts);
    // Fork in order to be able to unmount despite the chroot.
    let f = unsafe { fork() };
    if f == 0 {
    let c = std::ffi::CString::new("/home/pe/Projets/frix/store").unwrap();
    if unsafe { chroot(c.as_ptr()) } < 0 {
    println!("child {:?}", std::io::Error::last_os_error());
    }
    println!("{:?}\n{:?}", path_env, ld_env);
    let penv = CString::new(path_env).unwrap();
    let lenv = CString::new(ld_env).unwrap();
    unsafe {
    let c = std::ffi::CString::new(
    "/ailpe/store/tmp3/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",
    )
    .unwrap();
    execve(
    c.as_ptr(),
    [c.as_ptr(), std::ptr::null()].as_ptr(),
    [penv.as_ptr(), lenv.as_ptr(), std::ptr::null()].as_ptr(),
    );
    println!("execve {:?}", std::io::Error::last_os_error());
    }
    } else {
    let mut status = 0;
    unsafe { waitpid(f, &mut status, 0) };
    std::mem::drop(mounts);
    }
    }
    /*
    let lua = mlua::Lua::new();
    let map_table = lua.create_table().unwrap();
    map_table.set(1, "one").unwrap();
    map_table.set("two", 2).unwrap();
    lua.globals().set("map_table", map_table).unwrap();
    let derivation = lua
    .create_function(|st, t: mlua::Table| {
    t.for_each(|k: String, v: mlua::Value| {
    println!("{:?} {:?}", k, v);
    Ok(())
    }).unwrap();
    Ok(1)
    })
    .unwrap();
    lua.globals().set("__derivation", derivation).unwrap();
    let ubuntu = lua
    .create_function(|st, (t, name): (mlua::Table, String)| {
    t.for_each(|k: String, v: mlua::Value| {
    println!("{:?} {:?}", k, v);
    Ok(())
    }).unwrap();
    let mut t = st.create_table().unwrap();
    t.set(1, "one").unwrap();
    Ok(t)
    })
    .unwrap();
    lua.globals().set("__ubuntu", ubuntu).unwrap();
    let ubuntu_ctx = lua
    .create_function(|st: &mlua::Lua, t: mlua::Table| -> mlua::Result<mlua::Table> {
    t.for_each(|k: String, v: mlua::Value| {
    println!("{:?} {:?}", k, v);
    Ok(())
    }).unwrap();
    let mut t = st.create_table().unwrap();
    t.set(1, "one").unwrap();
    Ok(t)
    })
    .unwrap();
    lua.globals().set("__ubuntu_ctx", ubuntu_ctx).unwrap();
    lua.load(std::fs::read_to_string(&std::env::args().nth(1).unwrap()).unwrap())
    .exec()
    .unwrap();
    return;
    */
    #[tokio::main]
    async fn main() {
    tracing_subscriber::registry()
    .with(
    tracing_subscriber::EnvFilter::try_from_default_env()
    .unwrap_or_else(|_| String::new().into()),
    )
    .with(tracing_subscriber::fmt::layer())
    .init();
    let elpe = Elpe {
    deb_client: Arc::new(Client {
    c: lazy_init::Lazy::new(),
    mirror: "http://fr.archive.ubuntu.com/ubuntu".to_string(),
    store_path: Path::new("/home/pe/Projets/frix/store").to_path_buf(),
    in_release: None.into(),
    }),
    };
    let addr = "0.0.0.0:50051".parse().unwrap();
    tonic::transport::Server::builder()
    .add_service(elpe_server::ElpeServer::new(elpe))
    .serve(addr)
    .await
    .unwrap();
    /*
    let h_secu = c.in_release("noble-security").await.unwrap();
    let h = c.in_release("noble").await.unwrap();
    let p_secu = c.packages(&h_secu, "main", "amd64").await.unwrap();
    let p_main = c.packages(&h, "main", "amd64").await.unwrap();
    let p_universe = c.packages(&h, "universe", "amd64").await.unwrap();
    let index_secu = deb::Index::open(&p_secu).unwrap();
    let index_main = deb::Index::open(&p_main).unwrap();
    let index_universe = deb::Index::open(&p_universe).unwrap();
    let h = Arc::new(Mutex::new(HashMap::new()));
    let index = &[index_main, index_universe, index_secu];
    download_extract_deps(index, &c, h.clone(), "hello-traditional")
    .await
    .unwrap();
    download_extract_deps(index, &c, h.clone(), "bash-static")
    .await
    .unwrap();
    trace!("{:#?}", h);
    return;
    let pid = unsafe {
    syscall(
    SYS_clone3,
    &libc::clone_args {
    flags: (CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWNS) as u64,
    pidfd: 0,
    parent_tid: 0,
    child_tid: 0,
    stack: 0,
    stack_size: 0,
    tls: 0,
    set_tid: 0,
    set_tid_size: 0,
    cgroup: 0,
    exit_signal: SIGCHLD as u64,
    },
    std::mem::size_of::<libc::clone_args>(),
    )
    };
    println!("pid {:?}", pid);
    if pid == 0 {
    child(&[
    "/home/pe/Projets/frix/tmp",
    "/home/pe/Projets/frix/tmp2",
    "/home/pe/Projets/frix/tmp3",
    ]);
    } else {
    println!("{:?}", std::io::Error::last_os_error());
    let x = unsafe { waitpid(pid as i32, std::ptr::null_mut(), 0) };
    println!("x {:?}", x);
    }
    */
    }
  • file addition: lib.rs (----------)
    [0.15]
    use futures::StreamExt;
    use std::collections::HashMap;
    use std::path::PathBuf;
    use tempfile::NamedTempFile;
    use thiserror::*;
    use tracing::*;
    use std::sync::Arc;
    pub mod deb;
    pub mod extract;
    pub mod mount;
    #[derive(Debug, Error)]
    pub enum Error {
    #[error(transparent)]
    Deb(#[from] deb::Error),
    #[error(transparent)]
    IO(#[from] std::io::Error),
    #[error(transparent)]
    Persist(#[from] tempfile::PersistError),
    #[error(transparent)]
    Elf(#[from] elfedit::Error),
    #[error(transparent)]
    Reqwest(#[from] reqwest::Error),
    #[error("Signature error")]
    Signature,
    #[error("Hash: expected {expected}, got {got}.")]
    WrongHash { expected: String, got: String },
    #[error("Wrong size")]
    WrongSize,
    #[error("Wrong result symlink, expected {expected:?}, got {got:?}")]
    WrongResultSymlink { expected: PathBuf, got: PathBuf },
    }
    pub struct Client {
    // dest: PathBuf,
    pub c: lazy_init::Lazy<reqwest::Client>,
    pub mirror: String,
    pub store_path: PathBuf,
    pub in_release: tokio::sync::Mutex<Option<Arc<InRelease>>>,
    }
    #[derive(Debug)]
    struct Downloaded {
    path: PathBuf,
    }
    use sha2::Digest;
    use std::process::Stdio;
    use tokio::io::{AsyncBufReadExt, AsyncWriteExt};
    use tokio::process::Command;
    #[derive(Debug)]
    pub struct InRelease {
    hashed: HashMap<String, (usize, [u8; 32])>,
    release: std::borrow::Cow<'static, str>,
    }
    struct HashedWriter<W> {
    hasher: sha2::Sha256,
    w: W,
    }
    impl<W: std::io::Write> std::io::Write for HashedWriter<W> {
    fn write(&mut self, b: &[u8]) -> Result<usize, std::io::Error> {
    self.hasher.update(b);
    self.w.write_all(b).unwrap();
    Ok(b.len())
    }
    fn flush(&mut self) -> Result<(), std::io::Error> {
    self.w.flush()
    }
    }
    impl Client {
    fn client(&self) -> &reqwest::Client {
    self.c.get_or_create(|| reqwest::Client::new())
    }
    pub async fn packages(
    &self,
    in_release: &InRelease,
    component: &str,
    arch: &str,
    ) -> Result<PathBuf, Error> {
    let ref m = self.mirror;
    let ref release = in_release.release;
    let end = format!("{component}/binary-{arch}/Packages");
    let end_xz = format!("{component}/binary-{arch}/Packages.xz");
    let (size_xz, expected_hash_xz) = in_release.hashed.get(&end_xz).unwrap();
    let (size, expected_hash) = in_release.hashed.get(&end).unwrap();
    let expected_xz = data_encoding::BASE32_DNSSEC.encode(&*expected_hash_xz);
    let expected = data_encoding::BASE32_DNSSEC.encode(&*expected_hash);
    std::fs::create_dir_all(&self.store_path)?;
    let expected_path = self.store_path.join(&expected);
    if let Ok(_) = std::fs::metadata(&expected_path) {
    return Ok(expected_path);
    }
    let r = self
    .client()
    .get(&format!(
    "{m}/dists/{release}/{component}/binary-{arch}/Packages.xz"
    ))
    .send()
    .await?;
    let file_xz = NamedTempFile::new_in(&self.store_path)?;
    let file = NamedTempFile::new_in(&self.store_path)?;
    let mut xz_dec = xz2::write::XzDecoder::new(HashedWriter {
    w: std::fs::File::create(&file)?,
    hasher: sha2::Sha256::new(),
    });
    let mut f = tokio::fs::File::create(&file_xz).await?;
    let mut r = r.bytes_stream();
    let mut hasher_xz = sha2::Sha256::new();
    let mut total = 0;
    while let Some(item) = r.next().await {
    let item = item?;
    total += item.len();
    {
    // we can't use write_all here, since lzma has padding
    // at the end of the file and the xz2 crate rejects
    // the padding.
    use std::io::Write;
    let mut i = 0;
    loop {
    let n = xz_dec.write(&item[i..])?;
    if n == 0 {
    break;
    } else {
    i += n
    }
    }
    }
    hasher_xz.update(&item);
    f.write_all(&item).await?;
    }
    if total != *size_xz || xz_dec.total_out() != *size as u64 {
    return Err(Error::WrongSize);
    }
    let w = xz_dec.finish().unwrap();
    let got_xz = &hasher_xz.finalize()[..];
    let got = &w.hasher.finalize()[..];
    if got_xz == expected_hash_xz && got == expected_hash {
    let mut expected_path_xz = self.store_path.join(&expected_xz);
    expected_path_xz.set_extension("xz");
    file_xz.persist(&expected_path_xz)?;
    file.persist(&expected_path)?;
    Ok(expected_path)
    } else {
    Err(Error::WrongHash {
    expected: expected_xz,
    got: data_encoding::HEXLOWER.encode(&got),
    })
    }
    }
    pub async fn in_release<R: Into<std::borrow::Cow<'static, str>>>(
    &self,
    release: R,
    ) -> Result<Arc<InRelease>, Error> {
    let ref m = self.mirror;
    let release = release.into();
    let mut ubuntu = self.store_path.join("ubuntu");
    std::fs::create_dir_all(&ubuntu)?;
    ubuntu.push(&*release);
    let mut lock = self.in_release.lock().await;
    if let Some(l) = (&*lock).clone() {
    return Ok(l)
    }
    let f = tokio::fs::File::open(&ubuntu).await;
    if let Ok(f) = f {
    let release = Arc::new(self.read_in_release(release, f).await?);
    *lock = Some(release.clone());
    Ok(release)
    } else {
    let r = self
    .client()
    .get(&format!("{m}/dists/{release}/InRelease"))
    .send()
    .await?;
    eprintln!("writing to {:?}", ubuntu);
    let mut com = Command::new("sq")
    .arg("verify")
    .arg(&format!("--output={}", ubuntu.to_str().unwrap()))
    .stdin(Stdio::piped())
    .spawn()?;
    let mut i = com.stdin.take().unwrap();
    let mut r = r.bytes_stream();
    // Here we know `sq` doesn't start writing until consuming all
    // its stdin.
    while let Some(item) = r.next().await {
    i.write_all(&item?).await?;
    }
    std::mem::drop(i);
    let status = com.wait().await?;
    let result = if status.success() {
    self.read_in_release(release, tokio::fs::File::open(&ubuntu).await?)
    .await
    } else {
    Err(Error::Signature)
    };
    let release = Arc::new(result?);
    *lock = Some(release.clone());
    Ok(release)
    }
    }
    pub async fn read_in_release<R: tokio::io::AsyncRead + Unpin>(
    &self,
    release: std::borrow::Cow<'static, str>,
    o: R,
    ) -> Result<InRelease, Error> {
    let mut b = tokio::io::BufReader::new(o).lines();
    let mut result = HashMap::new();
    let mut recording = false;
    while let Some(l) = b.next_line().await? {
    if recording && l.starts_with(" ") {
    let mut s = l.split(' ').filter(|x| !x.is_empty());
    let hash = s.next().unwrap();
    let mut hash_ = [0; 32];
    data_encoding::HEXLOWER_PERMISSIVE
    .decode_mut(hash.as_bytes(), &mut hash_)
    .unwrap();
    let size = s.next().unwrap();
    let name = s.next().unwrap();
    result.insert(name.to_string(), (size.parse().unwrap(), hash_));
    } else {
    recording = l == "SHA256:";
    }
    }
    Ok(InRelease {
    release,
    hashed: result,
    })
    }
    fn url(&self, package: &deb::Stanza) -> String {
    let ref m = self.mirror;
    let filename = package.file_name.unwrap();
    format!("{m}/{filename}")
    }
    async fn download_url<'a>(&self, url: &str, sha256: &str) -> Result<(Downloaded, bool), Error> {
    let base = url.split('/').last().unwrap();
    let path = self.store_path.join(&format!("{}-{}", sha256, base));
    if tokio::fs::metadata(&path).await.is_ok() {
    return Ok((Downloaded { path }, false));
    }
    info!("download url {:?} {:?}", url, sha256);
    let r = self.client().get(url).send().await?;
    let mut s = r.bytes_stream();
    tokio::fs::create_dir_all(&self.store_path).await?;
    let mut hasher = sha2::Sha256::new();
    let mut f = tokio::fs::File::create(&path).await?;
    while let Some(item) = s.next().await {
    let item = item?;
    hasher.update(&item);
    f.write_all(&item).await?;
    }
    f.flush().await?;
    let hash = data_encoding::HEXLOWER_PERMISSIVE.encode(&hasher.finalize());
    if &hash != sha256 {
    return Err(Error::WrongHash {
    expected: sha256.to_string(),
    got: hash,
    });
    }
    Ok((Downloaded { path }, true))
    }
    }
  • file addition: extract.rs (----------)
    [0.15]
    use crate::{Client, Downloaded, Error};
    use std::collections::{BTreeSet, HashMap};
    use std::ffi::CString;
    use std::io::Write;
    use std::path::{Path, PathBuf};
    use std::sync::{Arc, Mutex};
    use tokio::sync::Semaphore;
    use tracing::*;
    use crate::deb;
    pub async fn download_extract_deps(
    index: &[deb::Index],
    client: &Arc<Client>,
    package: &str,
    ) -> Result<Vec<PathBuf>, Error> {
    let files = Arc::new(Mutex::new(HashMap::new()));
    let mut seen = HashMap::new();
    let pkg = multi_lookup(index, &package).unwrap();
    let mut stack = vec![StackElt {
    package: pkg,
    rx: None,
    deps: Vec::new(),
    deps_h: BTreeSet::new(),
    ld_path: Vec::new(),
    ld_path_h: BTreeSet::new(),
    }];
    let tasks = Arc::new(Semaphore::new(MAX_PARALLEL_DOWNLOADS));
    let mut result = Vec::new();
    while let Some(mut elt) = stack.pop() {
    info!("{:?}", elt);
    if let Some(rx) = elt.rx.take() {
    let downloaded = rx.await.unwrap();
    info!("downloaded {:?}", elt.package);
    elt.finalize(client, &files, downloaded, &mut stack, &mut result)
    .await?;
    seen.insert(elt.package.package, (elt.ld_path, elt.deps));
    } else {
    if let Some((ld_path, deps)) = seen.get(&elt.package.package) {
    if let Some(last) = stack.iter_mut().rev().filter(|x| x.rx.is_some()).next() {
    for ld in ld_path {
    if last.ld_path_h.insert(ld.clone()) {
    last.ld_path.push(ld.clone());
    }
    }
    for dep in deps {
    if last.deps_h.insert(dep.clone()) {
    last.deps.push(dep.clone());
    }
    }
    }
    continue;
    }
    use std::collections::hash_map::Entry;
    if let Entry::Vacant(e) = seen.entry(elt.package.package) {
    e.insert((Vec::new(), Vec::new()));
    } else {
    unreachable!()
    }
    let client = client.clone();
    let url = client.url(&elt.package);
    let sha256 = elt.package.sha256.unwrap().to_string();
    let (tx, rx) = tokio::sync::oneshot::channel();
    let files = files.clone();
    let tasks = tasks.clone();
    tokio::spawn(async move {
    let permit = tasks.acquire_owned().await.unwrap();
    info!("downloading {:?}", url);
    let (mut task, downloaded) = client.download_url(&url, &sha256).await.unwrap();
    info!("finished downloading {:?}", url);
    if downloaded {
    tokio::task::spawn_blocking(move || {
    extract_task(&mut task, &mut *files.lock().unwrap()).unwrap();
    info!("finished extracting {:?}", url);
    tx.send(task).unwrap_or(());
    info!("sent {:?}", url);
    })
    .await
    .unwrap();
    } else {
    task.path.set_extension("");
    let mut files = files.lock().unwrap();
    for f in find_files(task.path.clone()) {
    if let Ok(p) = f.strip_prefix(&task.path) {
    use std::collections::hash_map::Entry;
    if let Entry::Vacant(e) = files.entry(p.to_path_buf()) {
    debug!("cached {:?} -> {:?}", p, f);
    e.insert(task.path.clone());
    }
    }
    }
    tx.send(task).unwrap_or(());
    }
    std::mem::drop(permit);
    Ok::<_, Error>(())
    });
    elt.rx = Some(rx);
    push_deps(index, elt, &mut stack);
    }
    }
    Ok(result)
    }
    async fn hash_reader(
    mut reader: impl tokio::io::AsyncReadExt + std::marker::Unpin,
    hasher: &mut blake3::Hasher,
    ) -> std::io::Result<u64> {
    let mut buffer = [0; 65536];
    let mut total = 0;
    loop {
    match reader.read(&mut buffer).await {
    Ok(0) => return Ok(total),
    Ok(n) => {
    hasher.update(&buffer[..n]);
    total += n as u64;
    }
    Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
    Err(e) => return Err(e),
    }
    }
    }
    fn extract_task(
    download: &mut Downloaded,
    files: &mut HashMap<PathBuf, PathBuf>,
    ) -> Result<(), Error> {
    debug!("extracting {:?}", download);
    let mut f = std::io::BufReader::new(std::fs::File::open(&download.path)?);
    let d = deb::Deb::read(&mut f)?;
    download.path.set_extension("");
    std::fs::create_dir_all(&download.path)?;
    d.decompress(&mut f, &download.path, |path| {
    use std::collections::hash_map::Entry;
    let path = if let Ok(p) = path.strip_prefix(".") {
    p.to_path_buf()
    } else {
    path.to_path_buf()
    };
    debug!("extract {:?} -> {:?}", path, download.path);
    if let Entry::Vacant(e) = files.entry(path) {
    e.insert(download.path.clone());
    }
    })?;
    Ok(())
    }
    const MAX_PARALLEL_DOWNLOADS: usize = 20;
    fn multi_lookup<'a>(index: &'a [deb::Index], package: &str) -> Option<deb::Stanza<'a>> {
    for ind in index {
    if let Some(i) = ind.lookup(&package) {
    return Some(i);
    }
    }
    None
    }
    struct FindFiles {
    stack: Vec<(PathBuf, std::fs::Metadata, bool)>,
    }
    fn find_files(path: PathBuf) -> FindFiles {
    let meta = std::fs::metadata(&path).unwrap();
    FindFiles {
    stack: vec![(path, meta, false)],
    }
    }
    impl Iterator for FindFiles {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
    while let Some((p, meta, visited)) = self.stack.pop() {
    if visited {
    continue;
    }
    if let Ok(dir) = std::fs::read_dir(&p) {
    self.stack.push((p, meta, true));
    for e in dir {
    if let Ok(e) = e {
    self.stack.push((e.path(), e.metadata().unwrap(), false));
    }
    }
    } else if meta.is_file() || meta.is_symlink() {
    return Some(p);
    } else {
    error!("could not read {:?}", p);
    continue;
    }
    }
    None
    }
    }
    type Files = Arc<Mutex<HashMap<PathBuf, PathBuf>>>;
    impl<'a> StackElt<'a> {
    fn add_ld_paths(&mut self, path: &Path) -> Result<(), std::io::Error> {
    let mut ld_so = path.join("etc");
    ld_so.push("ld.so.conf.d");
    if let Ok(dir) = std::fs::read_dir(&ld_so) {
    for f in dir {
    let f = f?;
    if let Ok(f) = std::fs::read_to_string(&f.path()) {
    for path in f.lines().rev().filter(|x| !x.starts_with("#")) {
    let path = Path::new(path);
    if self.ld_path_h.insert(Arc::new(path.to_path_buf())) {
    self.ld_path.push(Arc::new(path.to_path_buf()))
    }
    }
    }
    }
    }
    if !self.ld_path.is_empty() {
    info!("ld_path: {:?}", self.ld_path)
    }
    Ok(())
    }
    fn find_libs(&mut self, path: &Path, dest: &Path) {
    for ld in self.ld_path.iter() {
    let path = path.join(ld.strip_prefix("/").unwrap());
    debug!("checking {:?}", path);
    if std::fs::metadata(&path).is_ok() {
    let path = Arc::new(dest.join(ld.strip_prefix("/").unwrap()));
    if self.deps_h.insert(path.clone()) {
    self.deps.push(path);
    }
    }
    }
    }
    fn patch_elf(&mut self, f: &Path, dest_path: &Path, files: &Files) -> Result<bool, Error> {
    use elfedit::*;
    info!("patch_elf {:?}", f);
    let file = std::fs::OpenOptions::new()
    .read(true)
    .write(true)
    .open(&f)?;
    let Ok(mut elf) = Elf::open(&file) else {
    return Ok(false);
    };
    info!("patching {:?}", f);
    let Some(parsed) = elf.parse().unwrap() else {
    info!("No dynamic section");
    return Ok(false);
    };
    let has_needed = parsed.needed().next().is_some();
    let interp = parsed.interpreter();
    if let Some(interp) = interp.unwrap() {
    let interp = interp.to_str().unwrap();
    let files = files.lock().unwrap();
    let p = Path::new(interp).strip_prefix("/").unwrap();
    let subst = if let Some(subst) = files.get(p) {
    subst.join(p)
    } else if interp.starts_with("/usr")
    || interp.starts_with("/lib")
    || interp.starts_with("/bin")
    {
    // https://www.freedesktop.org/wiki/Software/systemd/TheCaseForTheUsrMerge/
    let p2 = "usr".to_string() + interp;
    let p2 = Path::new(&p2);
    debug!("{:?}", p2);
    if let Some(subst) = files.get(p2) {
    subst.join(p2)
    } else {
    error!("No subst for {:?}", p2);
    let mut p2 = p2.to_path_buf();
    while p2.pop() {
    debug!("p2 = {:?} {:?}", p2, files.get(&p2));
    }
    return Ok(false);
    }
    } else {
    // TODO: not sure what else to do here, we
    // might want to set the interpreter to a
    // different value (equivalent to "recompiling
    // everything" on Nix).
    info!("Interpreter is {interp}. Already patched?");
    return Ok(false);
    };
    let subst = CString::new(subst.to_str().unwrap()).unwrap();
    info!("{:?}", subst);
    elf.set_interpreter(subst.to_bytes_with_nul());
    } else if !has_needed {
    // No need to patch
    return Ok(false);
    }
    let mut deps_h = BTreeSet::new();
    let mut path = String::new();
    for dep in self.deps.iter().rev() {
    debug!("dep = {:?}", dep);
    if !deps_h.insert(dep) {
    continue;
    }
    if !path.is_empty() {
    path.push(':')
    }
    path.push_str(dep.to_str().unwrap());
    }
    path.push('\0');
    info!("Setting path {:?}", path);
    if has_needed {
    elf.set_runpath(&path.as_bytes());
    }
    debug!("patching into {:?}", dest_path);
    Ok(elf.update(Some(dest_path)).unwrap()) // map_err(From::from)
    }
    async fn finalize(
    &mut self,
    client: &Client,
    files: &Files,
    downloaded: Downloaded,
    stack: &mut Vec<StackElt<'a>>,
    result: &mut Vec<PathBuf>,
    ) -> Result<(), Error> {
    let mut context_hasher = blake3::Hasher::new();
    context_hasher.update(self.package.sha256.unwrap().as_bytes());
    for d in self.deps.iter() {
    context_hasher.update(d.to_str().unwrap().as_bytes());
    }
    let dest = client
    .store_path
    .join(data_encoding::HEXLOWER.encode(context_hasher.finalize().as_bytes()));
    // Find the extra ld paths to look for.
    self.add_ld_paths(&downloaded.path).unwrap();
    let initial_deps_len = self.deps.len();
    // Find the libs in this package.
    self.find_libs(&downloaded.path, &dest);
    let base_package_name = self.package.file_name.unwrap().split('/').last().unwrap();
    let base_package_name = Path::new(&base_package_name).with_extension("");
    let base_package_name = base_package_name.to_str().unwrap();
    let final_path = if std::fs::metadata(&dest).is_err() {
    info!("patching");
    // Patch the ELFs, now that we have all the deps.
    let mut hashing = Vec::new();
    for f in find_files(downloaded.path.clone()) {
    let dest_path = dest.join(&f.strip_prefix(&downloaded.path).unwrap());
    std::fs::create_dir_all(dest_path.parent().unwrap()).unwrap();
    let patched = self.patch_elf(&f, &dest_path, &files).unwrap_or(false);
    if !patched {
    // Hard link
    debug!("hard link {:?} {:?}", f, dest_path);
    std::fs::hard_link(&f, &dest_path).unwrap_or(());
    }
    hashing.push(tokio::spawn(async move {
    // hash + write
    info!("hashing {:?}", f);
    if let Ok(link) = std::fs::read_link(&dest_path) {
    Ok(Some((dest_path, link.to_str().unwrap().to_string())))
    } else if let Ok(file) = tokio::fs::File::open(&dest_path).await {
    let mut hasher = blake3::Hasher::new();
    hash_reader(file, &mut hasher).await?;
    let hex = data_encoding::HEXLOWER.encode(hasher.finalize().as_bytes());
    Ok::<_, Error>(Some((f, hex)))
    } else {
    Ok(None)
    }
    }));
    }
    info!("patched all");
    let mut hashes = Vec::with_capacity(hashing.len());
    for h in hashing.into_iter() {
    if let Some(h) = h.await.unwrap().unwrap() {
    hashes.push(h)
    }
    }
    hashes.sort_by(|a, b| a.0.cmp(&b.0));
    info!("hashed all");
    let mut output_hasher = blake3::Hasher::new();
    let blakesums = dest.join("blake3sums");
    let mut file = std::fs::File::create(&blakesums).unwrap();
    for (path, hash) in hashes {
    debug!("strip {:?} {:?}", path, downloaded.path);
    let path = path.to_str().unwrap();
    writeln!(file, "{} {}", hash, path)?;
    writeln!(output_hasher, "{} {}", hash, path)?;
    }
    client.store_path.join(&format!(
    "{}-{}",
    data_encoding::HEXLOWER.encode(output_hasher.finalize().as_bytes()),
    base_package_name,
    ))
    } else {
    info!("found, no patching");
    let mut output_hasher = blake3::Hasher::new();
    let blakesums = dest.join("blake3sums");
    let file = tokio::fs::File::open(&blakesums).await.unwrap();
    hash_reader(file, &mut output_hasher).await?;
    client.store_path.join(&format!(
    "{}-{}",
    data_encoding::HEXLOWER.encode(output_hasher.finalize().as_bytes()),
    base_package_name,
    ))
    };
    // Replace prefix for all library deps we've just added,
    // in order to get a Merkle tree.
    for dep in &mut self.deps[initial_deps_len..] {
    let end = dep.strip_prefix(&dest).unwrap();
    *dep = Arc::new(final_path.join(&end));
    }
    info!("symlink {:?} {:?}", downloaded.path, final_path);
    match std::os::unix::fs::symlink(&dest, &final_path) {
    Ok(()) => (),
    Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
    let got = std::fs::read_link(&final_path)?;
    if dest != got {
    return Err(Error::WrongResultSymlink {
    expected: dest,
    got,
    });
    }
    }
    Err(e) => return Err(e.into()),
    }
    result.push(final_path);
    // Maintenant, faire remonter les deps.
    if let Some(last) = stack.iter_mut().rev().filter(|x| x.rx.is_some()).next() {
    for ld in self.ld_path.iter() {
    if last.ld_path_h.insert(ld.clone()) {
    last.ld_path.push(ld.clone());
    }
    }
    for dep in self.deps.iter() {
    if last.deps_h.insert(dep.clone()) {
    last.deps.push(dep.clone());
    }
    }
    }
    info!("done with {:?}", self.package.package);
    Ok(())
    }
    }
    fn push_deps<'a>(index: &'a [deb::Index], elt: StackElt<'a>, stack: &mut Vec<StackElt<'a>>) {
    let depends = elt.package.depends.clone();
    stack.push(elt);
    for dep in depends.iter() {
    match dep {
    deb::Dep::Simple(s) => {
    debug!("dep {:?}", s);
    let dep = multi_lookup(index, &s.name).unwrap();
    stack.push(StackElt {
    package: dep,
    rx: None,
    deps: Vec::new(),
    deps_h: BTreeSet::new(),
    ld_path: Vec::new(),
    ld_path_h: BTreeSet::new(),
    })
    }
    deb::Dep::Alternatives { alt } => {
    debug!("alt {:?}", alt);
    for dep in alt {
    if let Some(dep_) = multi_lookup(index, &dep.name) {
    stack.push(StackElt {
    package: dep_,
    rx: None,
    deps: Vec::new(),
    deps_h: BTreeSet::new(),
    ld_path: Vec::new(),
    ld_path_h: BTreeSet::new(),
    });
    return;
    }
    }
    panic!("Not found: {:?}", alt);
    }
    }
    }
    }
    #[derive(Debug)]
    struct StackElt<'a> {
    package: deb::Stanza<'a>,
    rx: Option<tokio::sync::oneshot::Receiver<Downloaded>>,
    deps: Vec<Arc<PathBuf>>,
    deps_h: BTreeSet<Arc<PathBuf>>,
    ld_path: Vec<Arc<PathBuf>>,
    ld_path_h: BTreeSet<Arc<PathBuf>>,
    }
  • file addition: deb.rs (----------)
    [0.15]
    use lazy_static::lazy_static;
    use std::collections::HashMap;
    use std::ffi::OsStr;
    use std::io::{BufRead, BufReader, Read, Seek, SeekFrom};
    use thiserror::*;
    use tracing::*;
    mod index;
    pub use index::*;
    /// A parsed .deb file.
    #[derive(Debug)]
    pub struct Deb {
    md5sums: HashMap<String, String>,
    control_file: String,
    global: Header,
    control: Header,
    data: Header,
    data_offset: u64,
    }
    /// A "stanza", i.e. a description of a Debian package.
    #[derive(Debug, Default, Clone)]
    pub struct Stanza<'a> {
    pub package: &'a str,
    pub version: Version<'a>,
    pub architecture: &'a str,
    pub depends: Vec<Dep<'a>>,
    pub sha256: Option<&'a str>,
    pub size: Option<usize>,
    pub file_name: Option<&'a str>,
    }
    /// A dependency, which is either a "simple" dependency, or a list of
    /// alternatives.
    #[derive(Debug, Clone)]
    pub enum Dep<'a> {
    Simple(SimpleDep<'a>),
    Alternatives { alt: Vec<SimpleDep<'a>> },
    }
    /// A single dependency.
    #[derive(Debug, Clone)]
    pub struct SimpleDep<'a> {
    pub name: &'a str,
    pub any: bool,
    pub constraints: Vec<(&'a str, Version<'a>)>,
    }
    fn parse_control(s: &str) -> IResult<&str, Stanza> {
    let mut st = Stanza::default();
    for l in s.lines() {
    if l.is_empty() {
    let (_, b) = s.split_at(l.as_ptr() as usize - s.as_ptr() as usize);
    return Ok((b, st));
    }
    if let Some(i) = l.find(':') {
    let (key, val) = l.split_at(i);
    let (_, val) = val.split_at(1);
    debug!("key {:?} {:?}", key, val);
    match key.trim() {
    "Package" => st.package = val.trim(),
    "Version" => st.version = parse_version(val.trim()).unwrap().1,
    "Architecture" => st.architecture = val.trim(),
    "SHA256" => st.sha256 = Some(val.trim()),
    "Filename" => st.file_name = Some(val.trim()),
    "Depends" | "Pre-Depends" => {
    let d = parse_deps(val.trim());
    debug!("{:?}", d);
    if let Ok(("", a)) = d {
    st.depends = a
    } else {
    error!("error {:?}", val.trim());
    return nom::IResult::Err(nom::Err::Error(nom::error::make_error(
    s,
    nom::error::ErrorKind::Tag,
    )));
    }
    }
    _ => {}
    }
    }
    }
    Ok(("", st))
    }
    /// A version of a package.
    ///
    /// Debian versions have mechanisms to override upstream ones, such as
    /// the "epoch" prefix to reorder versions if necessary, and the
    /// "debian" suffix to add specifics.
    #[derive(Debug, Clone)]
    pub struct Version<'a> {
    pub epoch: u32,
    pub upstream_version: Upstream<'a>,
    pub debian: Option<&'a str>,
    }
    impl<'a> Default for Version<'a> {
    fn default() -> Version<'a> {
    Version {
    epoch: 0,
    upstream_version: Upstream(""),
    debian: None,
    }
    }
    }
    fn parse_constraint<'a>(s: &'a str) -> IResult<&'a str, (&'a str, Version<'a>)> {
    let (s, constraint) = tag("<<")
    .or(tag("<="))
    .or(tag("="))
    .or(tag(">="))
    .or(tag(">>"))
    .parse(s)?;
    debug!("parse_constraint {:?}", constraint);
    let (s, _) = space0(s)?;
    let (s, version) = parse_version(s)?;
    debug!("parse_constraint {:?} {:?}", s, (constraint, &version));
    Ok((s, (constraint, version)))
    }
    fn parse_dep<'a>(s0: &'a str) -> IResult<&'a str, Dep<'a>> {
    let (s, name) = parse_name(s0)?;
    let (s, any) = if s.starts_with(":any") {
    let (_, b) = s.split_at(4);
    (b, true)
    } else {
    (s, false)
    };
    let (s, _) = space0(s)?;
    let mut constraints = Vec::new();
    if let Ok((s, _)) = tag::<_, _, ()>("(").parse(s) {
    let (s, version) = if let Some(i) = s.find(')') {
    let (a, b) = s.split_at(i);
    let (_, b) = b.split_at(1);
    (b, a)
    } else {
    return nom::IResult::Err(nom::Err::Error(nom::error::make_error(
    s,
    nom::error::ErrorKind::Tag,
    )));
    };
    let mut v = version;
    while let Ok((v_, c)) = parse_constraint(v) {
    constraints.push(c);
    let (v_, _) = space0(v_)?;
    if let Ok((v_, _)) = tag::<_, _, ()>(",").parse(v_) {
    let (v_, _) = space0(v_)?;
    v = v_;
    } else {
    break;
    }
    }
    Ok((
    s,
    Dep::Simple(SimpleDep {
    name,
    any,
    constraints,
    }),
    ))
    } else {
    Ok((
    s,
    Dep::Simple(SimpleDep {
    name,
    any,
    constraints,
    }),
    ))
    }
    }
    fn parse_name(s: &str) -> IResult<&str, &str> {
    if let Some(i) = s.find(|c| {
    !((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '+' || c == '-')
    }) {
    if i > 0 {
    let (a, b) = s.split_at(i);
    return Ok((b, a));
    }
    } else {
    return Ok(("", s));
    }
    error!("ERROR {:?}", s);
    return nom::IResult::Err(nom::Err::Error(nom::error::make_error(
    s,
    nom::error::ErrorKind::Tag,
    )));
    }
    fn parse_deps<'a>(s: &'a str) -> IResult<&'a str, Vec<Dep<'a>>> {
    let mut d = Vec::new();
    let (mut s, _) = space0(s)?;
    while let Ok((s_, d_)) = parse_dep(s) {
    debug!("parse_dep {:?}", d_);
    let (s_, _) = space0(s_)?;
    if let Ok((s_, _)) = tag::<_, _, ()>("|").parse(s_) {
    let (s_, _) = space0(s_)?;
    s = s_;
    match d.pop() {
    Some(Dep::Alternatives { ref mut alt }) => {
    if let Dep::Simple(d_) = d_ {
    alt.push(d_)
    }
    }
    _ => {
    if let Dep::Simple(d_) = d_ {
    d.push(Dep::Alternatives { alt: vec![d_] })
    }
    }
    }
    } else if let Ok((s_, _)) = tag::<_, _, ()>(",").parse(s_) {
    d.push(d_);
    s = s_;
    } else {
    d.push(d_);
    s = s_;
    break;
    }
    let (s_, _) = space0(s)?;
    s = s_;
    }
    Ok((s, d))
    }
    /// The representation of an upstream version. Will implement `Ord`.
    #[derive(Debug, Clone)]
    pub struct Upstream<'a>(&'a str);
    use nom::{
    IResult, Parser,
    bytes::tag,
    character::complete::{digit1, newline, space0},
    multi::separated_list1,
    };
    /// Parse a version in the Debian version format.
    fn parse_version<'a>(s: &'a str) -> IResult<&'a str, Version<'a>> {
    fn epoch(s: &str) -> IResult<&str, u32> {
    let (s, i) = digit1(s)?;
    let (s, _) = tag(":").parse(s)?;
    Ok((s, i.parse().unwrap()))
    }
    let (s, epoch) = epoch(s).unwrap_or((s, 0));
    lazy_static! {
    static ref RE_DASH: regex::Regex =
    regex::Regex::new(r"^[a-z0-9.~+-]+-([a-z0-9.~+]+)").unwrap();
    static ref RE: regex::Regex = regex::Regex::new(r"^[a-z0-9.~+]+").unwrap();
    }
    let (s, v) = if let Some(m) = RE_DASH.find(s) {
    let (a, b) = s.split_at(m.end());
    (b, a)
    } else if let Some(m) = RE.find(s) {
    let (a, b) = s.split_at(m.end());
    (b, a)
    } else {
    return nom::IResult::Err(nom::Err::Error(nom::error::make_error(
    s,
    nom::error::ErrorKind::Tag,
    )));
    };
    let (upstream_version, debian) = if let Some(i) = v.rfind('-') {
    let (a, b) = v.split_at(i);
    (Upstream(a), Some(b.split_at(1).1))
    } else {
    (Upstream(v), None)
    };
    Ok((
    s,
    Version {
    epoch,
    upstream_version,
    debian,
    },
    ))
    }
    /// Structure of the "headers" in the debian file. No alignment
    /// necessary, the numbers are in decimal. No heap allocation.
    #[derive(Debug)]
    #[repr(C)]
    struct H {
    file_id: [u8; 16],
    timestamp: [u8; 12],
    owner_id: [u8; 6],
    group_id: [u8; 6],
    file_mode: [u8; 8],
    file_size: [u8; 10],
    end_char: [u8; 2],
    }
    /// Parsed version of `H`, still no heap allocation.
    #[derive(Debug)]
    struct Header {
    file_id: [u8; 16],
    timestamp: u64,
    owner_id: u32,
    group_id: u32,
    file_mode: u32,
    file_size: u64,
    }
    /// Possible errors for .deb files.
    #[derive(Debug, Error)]
    pub enum Error {
    #[error("Deb file parse error")]
    ParseError,
    #[error(transparent)]
    Utf8(#[from] std::str::Utf8Error),
    #[error(transparent)]
    Int(#[from] std::num::ParseIntError),
    #[error(transparent)]
    IO(#[from] std::io::Error),
    #[error("Unsupported compression algorithm: {file_id}")]
    UnsupportedCompression { file_id: String },
    #[error("Version parse: {version}")]
    Version { version: String },
    }
    impl Header {
    pub fn file_id(&self) -> &str {
    unsafe { std::str::from_utf8_unchecked(&self.file_id).trim() }
    }
    }
    impl H {
    fn parse(&self) -> Result<Header, Error> {
    std::str::from_utf8(&self.file_id)?;
    Ok(Header {
    file_id: self.file_id,
    timestamp: std::str::from_utf8(&self.timestamp)?.trim().parse()?,
    owner_id: std::str::from_utf8(&self.owner_id)?.trim().parse()?,
    group_id: std::str::from_utf8(&self.group_id)?.trim().parse().unwrap(),
    file_mode: u32::from_str_radix(std::str::from_utf8(&self.file_mode)?.trim(), 8)?,
    file_size: std::str::from_utf8(&self.file_size)?.trim().parse()?,
    })
    }
    }
    fn read_hdr<R: Read>(r: &mut R) -> Result<Header, Error> {
    unsafe {
    assert_eq!(std::mem::size_of::<H>(), HEADER_SIZE as usize);
    let mut b: H = std::mem::zeroed();
    r.read_exact(&mut std::slice::from_raw_parts_mut(
    &mut b as *mut H as *mut u8,
    std::mem::size_of::<H>(),
    ))?;
    debug!("{:?}", b);
    b.parse()
    }
    }
    const HEADER_SIZE: u64 = 60;
    const SIGNATURE_SIZE: u64 = 8;
    impl Deb {
    pub fn parse_control(&self) -> Vec<Stanza> {
    if let Ok(("", st)) = separated_list1(newline, parse_control).parse(&self.control_file) {
    st
    } else {
    Vec::new()
    }
    }
    pub fn md5sums(&self) -> &HashMap<String, String> {
    &self.md5sums
    }
    pub fn decompress<R: BufRead + Seek, P: AsRef<std::path::Path>, F: FnMut(&std::path::Path)>(
    &self,
    mut r: R,
    path: P,
    mut f: F,
    ) -> Result<(), Error> {
    r.seek(SeekFrom::Start(self.data_offset))?;
    debug!("decompress {:?}", self.data.file_id());
    if self.data.file_id().ends_with(".tar.gz") {
    unimplemented!()
    } else if self.data.file_id().ends_with(".tar.zst") {
    let mut ar = tar::Archive::new(
    zstd::stream::read::Decoder::new(r.take(self.data.file_size)).unwrap(),
    );
    for e in ar.entries()? {
    let mut e = e?;
    f(&e.path()?);
    e.unpack_in(&path)?;
    }
    } else {
    unimplemented!()
    };
    Ok(())
    }
    pub fn read<R: BufRead + Seek>(mut r: R) -> Result<Deb, Error> {
    let mut b = [0; 8];
    r.read_exact(&mut b)?;
    if &b != b"!<arch>\n" {
    return Err(Error::ParseError);
    }
    let global = read_hdr(&mut r)?;
    trace!("GLOBAL {:?}", global);
    r.seek(SeekFrom::Current(global.file_size as i64))?;
    r.skip_until(b'c')?; // 'control.…'
    r.seek(SeekFrom::Current(-1))?;
    let control = read_hdr(&mut r)?;
    trace!("CONTROL {:?}", control);
    // Control files are expected to be short, decompress.
    let mut ctrl = vec![0; control.file_size as usize];
    r.read_exact(&mut ctrl)?;
    // gzip xz zstd none
    let ctrl_tar = if control.file_id().ends_with(".tar.gz") {
    unimplemented!()
    } else if control.file_id().ends_with(".tar.zst") {
    zstd::decode_all(&ctrl[..])?
    } else if control.file_id().ends_with(".tar.xz") {
    unimplemented!()
    } else if control.file_id().ends_with(".tar") {
    ctrl
    } else {
    return Err(Error::UnsupportedCompression {
    file_id: control.file_id().to_string(),
    });
    };
    let mut ctrl_tar = tar::Archive::new(&ctrl_tar[..]);
    let mut control_file = String::new();
    let mut md5sums = HashMap::new();
    for e in ctrl_tar.entries().unwrap() {
    let mut e = e.unwrap();
    if e.path()?.file_name() == Some(OsStr::new("control")) {
    e.read_to_string(&mut control_file)?;
    } else if e.path()?.file_name() == Some(OsStr::new("md5sums")) {
    let mut e = BufReader::new(e);
    let mut s = String::new();
    while e.read_line(&mut s)? > 0 {
    let mut it = s.split(' ').filter(|x| !x.is_empty());
    if let (Some(hash), Some(file)) = (it.next(), it.next()) {
    md5sums.insert(file.trim().to_string(), hash.trim().to_string());
    }
    s.clear();
    }
    }
    }
    r.seek(SeekFrom::Start(
    SIGNATURE_SIZE + 2 * HEADER_SIZE + control.file_size,
    ))?;
    r.skip_until(b'd')?; // 'data.…'
    r.seek(SeekFrom::Current(-1))?;
    let data = read_hdr(&mut r)?;
    Ok(Deb {
    md5sums,
    global,
    control,
    control_file,
    data,
    data_offset: r.seek(SeekFrom::Current(0))?,
    })
    }
    }
  • file addition: deb (d--r------)
    [0.15]
  • file addition: index.rs (----------)
    [0.51845]
    use super::{Stanza, parse_control};
    use tracing::*;
    use std::num::NonZeroUsize;
    use std::sync::{Arc, Mutex};
    /// The index of a package repository.
    ///
    /// These files are made of many stanzas sorted in lexicographical
    /// order of the package name. Internally this is represented as a
    /// memory-mapped file.
    pub struct Index {
    map: memmap::Mmap,
    lru: Arc<Mutex<lru::LruCache<String, Option<(usize, usize)>>>>,
    }
    impl Index {
    pub fn open<P: AsRef<std::path::Path>>(f: P) -> Result<Self, std::io::Error> {
    let file = std::fs::File::open(f)?;
    let mmap = unsafe { memmap::MmapOptions::new().map(&file)? };
    Ok(Index {
    map: mmap,
    lru: Arc::new(Mutex::new(lru::LruCache::new(NonZeroUsize::new(256).unwrap()))),
    })
    }
    pub fn lookup(&self, package: &str) -> Option<Stanza> {
    info!("Looking up {:?}", package);
    let s = &*self.map;
    match self.lru.lock().unwrap().get(package) {
    Some(Some((m1, m2))) => {
    let line = std::str::from_utf8(&s[*m1..*m2]).unwrap().trim();
    let (_, st) = parse_control(line).unwrap();
    return Some(st)
    }
    Some(None) => {
    return None
    },
    None => {},
    }
    let mut a = 0;
    let mut b = s.len();
    // Now, dichotomy.
    loop {
    debug!(
    "a = {:?}",
    std::str::from_utf8(&s[a..s.len().min(a + 30)]).unwrap()
    );
    debug!(
    "b = {:?}",
    std::str::from_utf8(&s[b..s.len().min(b + 30)]).unwrap()
    );
    let mut m1 = (a + b) / 2;
    while m1 > a && (s[m1] != b'\n' || s[m1 + 1] != b'\n') {
    m1 -= 1;
    }
    let mut m2 = m1 + 2;
    while m2 + 1 < b && (s[m2] != b'\n' || s[m2 + 1] != b'\n') {
    m2 += 1;
    }
    if m2 < b {
    m2 += 1
    }
    let line = std::str::from_utf8(&s[m1..m2]).unwrap().trim();
    if line.is_empty() {
    // This may happen if b = a + 1.
    debug!("not found: {:?}", package);
    self.lru.lock().unwrap().put(package.to_string(), None);
    return None;
    }
    debug!("line {:?}", line);
    if let Ok((_, st)) = parse_control(line) {
    debug!("package: {:?}", st.package);
    if st.package == package {
    debug!("found {:?}", package);
    self.lru.lock().unwrap().put(package.to_string(), Some((m1, m2)));
    return Some(st);
    } else if st.package < package {
    debug!("smaller");
    a = m2
    } else {
    debug!("greater");
    b = m1
    }
    } else {
    panic!("parse {:?}", line);
    }
    if a >= b {
    debug!(
    "break a = {:?}",
    std::str::from_utf8(&s[a..s.len().min(a + 30)]).unwrap()
    );
    debug!(
    "break b = {:?}",
    std::str::from_utf8(&s[b..s.len().min(b + 30)]).unwrap()
    );
    break;
    }
    }
    debug!("not found 2: {:?}", package);
    self.lru.lock().unwrap().put(package.to_string(), None);
    None
    }
    }
  • file addition: elpe (d--r------)
    [2.1]
  • file addition: lib (d--r------)
    [0.55432]
  • file addition: elpegrpc.proto (----------)
    [0.55449]
    syntax = "proto3";
    package elpe;
    message DerivationRequest {
    string name = 1;
    string builder = 2;
    }
    message DerivationReply {
    repeated string path = 1;
    optional string error = 2;
    }
    enum Arch {
    amd64 = 0;
    aarch64 = 1;
    }
    message UbuntuReleaseRequest {
    string release = 1;
    Arch arch = 2;
    string repository = 3;
    }
    message UbuntuPackageRequest {
    repeated string index = 1;
    string name = 2;
    }
    service Elpe {
    rpc Derivation (DerivationRequest) returns (DerivationReply);
    rpc UbuntuRelease (UbuntuReleaseRequest) returns (DerivationReply);
    rpc UbuntuPackage (UbuntuPackageRequest) returns (DerivationReply);
    }
  • file addition: elpe.ml (----------)
    [0.55449]
    open Grpc_lwt
    open Lwt.Syntax
    exception Error of H2.Client_connection.error
    let connection address port =
    (* Setup Http/2 connection *)
    let* addresses =
    Lwt_unix.getaddrinfo address (string_of_int port)
    [ Unix.(AI_FAMILY PF_INET) ]
    in
    let socket = Lwt_unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
    let* () = Lwt_unix.connect socket (List.hd addresses).Unix.ai_addr in
    let error_handler e =
    raise (Error e)
    in
    H2_lwt_unix.Client.create_connection ~error_handler socket
    let ubuntu_release connection ~release ~arch ~repository =
    let req =
    Elpegrpc.Elpe.UbuntuReleaseRequest.make ~release ~arch ~repository ()
    in
    let open Ocaml_protoc_plugin in
    let open Elpegrpc.Elpe in
    let encode, decode = Service.make_client_functions Elpe.ubuntuRelease in
    let enc = encode req |> Writer.contents in
    Client.call ~service:"elpe.Elpe" ~rpc:"UbuntuRelease"
    ~do_request:
    (H2_lwt_unix.Client.request connection ~error_handler:(fun _ ->
    failwith "Error"))
    ~handler:
    (Client.Rpc.unary enc ~f:(fun decoder ->
    let+ decoder = decoder in
    match decoder with
    | Some decoder -> (
    Reader.create decoder |> decode |> function
    | Ok v -> v
    | Error e ->
    failwith
    (Printf.sprintf "Could not decode request: %s"
    (Result.show_error e)))
    | None -> Elpe.Derivation.Response.make ()))
    ()
    let ubuntu_package connection ~index ~name =
    let req = Elpegrpc.Elpe.UbuntuPackageRequest.make ~index ~name () in
    let open Ocaml_protoc_plugin in
    let open Elpegrpc.Elpe in
    let encode, decode = Service.make_client_functions Elpe.ubuntuPackage in
    let enc = encode req |> Writer.contents in
    Client.call ~service:"elpe.Elpe" ~rpc:"UbuntuPackage"
    ~do_request:
    (H2_lwt_unix.Client.request connection ~error_handler:(fun _ ->
    failwith "Error"))
    ~handler:
    (Client.Rpc.unary enc ~f:(fun decoder ->
    let+ decoder = decoder in
    match decoder with
    | Some decoder -> (
    Reader.create decoder |> decode |> function
    | Ok v -> v
    | Error e ->
    failwith
    (Printf.sprintf "Could not decode request: %s"
    (Result.show_error e)))
    | None -> Elpe.Derivation.Response.make ()))
    ()
    class virtual derivation =
    object (self)
    method virtual name : string
    method setup : string list Lwt.t = Lwt.return []
    method build : string list Lwt.t = self#setup
    end
    let backend_conn = ref None
    let ubuntu name =
    object
    inherit derivation
    method name = name
    method! build =
    let c =
    match !backend_conn with None -> failwith "no conn" | Some c -> c
    in
    let* index =
    Lwt_list.map_p
    (fun repository ->
    let* res =
    ubuntu_release c ~release:"noble" ~arch:Amd64 ~repository
    in
    let res, _ = Result.get_ok res in
    Lwt.return res.path)
    [ "main"; "universe" ]
    in
    let index = List.concat index in
    let* res = ubuntu_package c ~index ~name in
    let res, _ = Result.get_ok res in
    Lwt.return res.path
    end
    class virtual std_derivation =
    object (self)
    inherit derivation
    method environment : (string * string) List.t Lwt.t = Lwt.return []
    method build_inputs : derivation list Lwt.t = Lwt.return []
    method! setup =
    let* bash = (ubuntu "bash-static")#build in
    let bash = List.hd bash in
    let* b = self#build_inputs in
    let* b =
    Lwt_list.map_p
    (fun d ->
    let* p = d#build in
    Lwt.return (List.map (fun p -> p ^ "/usr/bin") p))
    b
    in
    let path =
    List.fold_left
    (List.fold_left (fun acc x -> if acc == "" then x else acc ^ ":" ^ x))
    "" b
    in
    Lwt.return [ "#!" ^ bash ^ "\n" ^ "export PATH=" ^ path ^ "\n" ]
    end
    let last_built_module : std_derivation option ref = ref None
    let build (spec : std_derivation) = last_built_module := Some spec
    let run_shell (spec : std_derivation) cmd =
    Lwt_main.run
    (let open Lwt.Syntax in
    let port = 50051 in
    let address = "127.0.0.1" in
    let* c = connection address port in
    backend_conn := Some c;
    let* b = spec#setup in
    let* bash = (ubuntu "bash-static")#build in
    let bash = List.hd bash in
    let f = Filename.temp_dir "elpe-" "" ^ "/setup" in
    Unix.mkfifo f 0o666;
    let pid =
    Unix.create_process
    (bash ^ "/usr/bin/bash-static")
    (match cmd with
    | None -> [| "bash"; "--init-file"; f; "-i" |]
    | Some cmd -> [| "bash"; "--init-file"; f; "-i"; "-c"; cmd |])
    Unix.stdin Unix.stdout Unix.stderr
    in
    let p = Unix.openfile f [ Unix.O_WRONLY ] 0o644 in
    List.fold_left
    (fun () b ->
    let _ = Unix.write_substring p b 0 (String.length b) in
    ())
    () b;
    Unix.close p;
    match Unix.waitpid [] pid with
    | _, Unix.WEXITED e -> Lwt.return e
    | _ -> failwith "Unknown")
    let run_build (spec : derivation) =
    Lwt_main.run
    (let open Lwt.Syntax in
    let port = 50051 in
    let address = "127.0.0.1" in
    let* c = connection address port in
    backend_conn := Some c;
    let* b = spec#build in
    let* bash = (ubuntu "bash-static")#build in
    let bash = List.hd bash in
    let f = Filename.temp_dir "elpe-" "" ^ "/setup" in
    Unix.mkfifo f 0o666;
    let pid =
    Unix.create_process
    (bash ^ "/usr/bin/bash-static")
    [| "bash"; "--init-file"; f; "-i" |]
    Unix.stdin Unix.stdout Unix.stderr
    in
    let p = Unix.openfile f [ Unix.O_WRONLY ] 0o644 in
    List.fold_left
    (fun () b ->
    let _ = Unix.write_substring p b 0 (String.length b) in
    ())
    () b;
    Unix.close p;
    let _ =
    match Unix.waitpid [] pid with
    | _, Unix.WEXITED e -> print_endline ("ended waitpid " ^ string_of_int e)
    | _ -> print_endline "other"
    in
    Lwt.return ())
  • file addition: dune (----------)
    [0.55449]
    (library
    (name elpe)
    (public_name elpe)
    (modes byte)
    (libraries grpc-lwt lwt lwt.unix h2 h2-lwt-unix pbrt ocaml-protoc-plugin))
    (rule
    (targets elpegrpc.ml)
    (deps
    (:proto elpegrpc.proto))
    (action
    (run
    protoc
    -I
    .
    "--ocaml_out=annot=[@@deriving show { with_path = false }]:."
    %{proto})))
  • file addition: dune-project (----------)
    [0.55432]
    (lang dune 3.17)
    (name elpegrpc)
    ; (generate_opam_files true)
    (authors "Author Name <author@example.com>")
    (maintainers "Maintainer Name <maintainer@example.com>")
    (license LICENSE)
    (documentation https://url/to/documentation)
    (package
    (name elpe-bin)
    (depends ocaml elpe lwt)
    )
    (package
    (name elpe)
    (depends ocaml lwt grpc-lwt h2-lwt-unix pbrt ocaml-protoc-plugin protoc)
    )
    ; See the complete stanza docs at https://dune.readthedocs.io/en/stable/reference/dune-project/index.html
  • file addition: bin (d--r------)
    [0.55432]
  • file addition: elpe_bin.ml (----------)
    [0.63240]
    open Elpe
    let usage_msg = "elpe [-verbose] [-c <command>] <file1> [<file2>]"
    let verbose = ref false
    let cmd = ref ""
    let input_files = ref []
    let anon_fun filename = input_files := filename :: !input_files
    let speclist =
    [
    ("-verbose", Arg.Set verbose, "Output debug information");
    ("-c", Arg.Set_string cmd, "Run the specified command");
    ]
    let compile_and_run () =
    (* Compile *)
    let args =
    Array.of_list
    ([
    "ocamlfind";
    (if Dynlink.is_native then "ocamlopt" else "ocamlc");
    "-package";
    "elpe";
    "-c";
    ]
    @ !input_files)
    in
    let pid =
    let rd, wr = Unix.pipe () in
    let pid = Unix.create_process "ocamlfind" args rd Unix.stdout Unix.stderr in
    Unix.close wr;
    pid
    in
    let _ =
    match Unix.waitpid [] pid with
    | _, Unix.WEXITED 0 -> ()
    | _, Unix.WEXITED e -> Unix._exit e
    | _ -> print_endline "other"
    in
    (* Link *)
    let obj =
    Dynlink.adapt_filename
    (Filename.remove_extension (Array.get args (Array.length args - 1))
    ^ ".cmo")
    in
    Dynlink.loadfile obj;
    match !last_built_module with
    | None -> 0
    | Some last ->
    run_shell last (if String.length !cmd == 0 then None else Some !cmd)
    let () =
    Arg.parse speclist anon_fun usage_msg;
    if !input_files != [] then
    let exit = compile_and_run () in
    Unix._exit exit
    else Printf.eprintf "\n"
  • file addition: dune (----------)
    [0.63240]
    (executable
    (name elpe_bin)
    (public_name elpe)
    (package elpe-bin)
    (modes byte)
    (libraries elpe grpc-lwt dynlink))
  • file addition: .ocamlformat (----------)
    [0.55432]
    version=0.27.0
    profile=default
  • file addition: default.nix (----------)
    [2.1]
    with import <nixpkgs> {};
    let luau = stdenv.mkDerivation rec {
    pname = "luau";
    version = "0.621";
    src = fetchFromGitHub {
    owner = "luau-lang";
    repo = "luau";
    rev = version;
    hash = "sha256-bkuYYGYcnMwQDK81ZH+74hA4XaQfVFMWvAKpy+ODCak=";
    };
    nativeBuildInputs = [ cmake pkg-config ];
    buildInputs = lib.optionals stdenv.cc.isClang [ llvmPackages.libunwind ];
    installPhase = ''
    runHook preInstall
    install -Dm755 -t $out/bin luau
    install -Dm755 -t $out/bin luau-analyze
    install -Dm755 -t $out/bin luau-compile
    install -Dm755 -t $out/lib lib*
    runHook postInstall
    '';
    # doCheck = true;
    # checkPhase = ''
    # runHook preCheck
    # ./Luau.UnitTest
    # ./Luau.Conformance
    # runHook postCheck
    # '';
    # passthru.updateScript = gitUpdater { };
    meta = with lib; {
    description = "Fast, small, safe, gradually typed embeddable scripting language derived from Lua";
    homepage = "https://luau-lang.org/";
    changelog = "https://github.com/luau-lang/luau/releases/tag/${version}";
    license = licenses.mit;
    platforms = platforms.all;
    maintainers = [ ];
    mainProgram = "luau";
    };
    };
    # grpc-async = ocamlPackages.buildDunePackage rec {
    # pname = "gprc-async";
    # version = "0.2.0";
    # src = builtins.fetchurl {
    # url = "https://github.com/emilpriver/jsoo-code-mirror/archive/refs/tags/v0.0.1.tar.gz";
    # sha256 = "sha256:0rby6kd9973icp72fj8i07awibamwsi3afy71dhrbq771dgz16cq";
    # };
    # propagatedBuildInputs = with pkgs; [
    # ocamlPackages.brr
    # ocamlPackages.js_of_ocaml
    # ];
    # };
    gluten-async = ocamlPackages.buildDunePackage rec {
    pname = "gluten-async";
    version = "0.5.2";
    src = pkgs.fetchurl {
    url = "https://github.com/anmonteiro/gluten/releases/download/0.5.2/gluten-0.5.2.tbz";
    sha256 = "sha256:0pq1ww3p41m6dzk2cmrr7pq03kvb5hjqvk49s95vp030kygxivmi";
    };
    propagatedBuildInputs = with pkgs; [
    ocamlPackages.gluten
    ocamlPackages.faraday-async
    ocamlPackages.async
    ocamlPackages.async_ssl
    ocamlPackages.tls-async
    ];
    };
    h2-lwt = ocamlPackages.buildDunePackage rec {
    pname = "h2-lwt";
    version = "0.12.0";
    src = pkgs.fetchurl {
    url = "https://github.com/anmonteiro/ocaml-h2/releases/download/0.12.0/h2-0.12.0.tbz";
    sha256 = "sha256-NuQLET2Q6jg2GajHvZk/hmExw8XZV2GbaEnrMq+MU8Y=";
    };
    propagatedBuildInputs = with pkgs; [
    h2
    ocamlPackages.faraday-async
    ocamlPackages.gluten-lwt
    gluten-async
    ];
    };
    h2-lwt-unix = ocamlPackages.buildDunePackage rec {
    pname = "h2-lwt-unix";
    version = "0.12.0";
    src = pkgs.fetchurl {
    url = "https://github.com/anmonteiro/ocaml-h2/releases/download/0.12.0/h2-0.12.0.tbz";
    sha256 = "sha256-NuQLET2Q6jg2GajHvZk/hmExw8XZV2GbaEnrMq+MU8Y=";
    };
    propagatedBuildInputs = with pkgs; [
    h2-lwt
    ocamlPackages.faraday-lwt-unix
    ocamlPackages.gluten-lwt-unix
    ];
    };
    h2 = ocamlPackages.buildDunePackage rec {
    pname = "h2";
    version = "0.12.0";
    src = pkgs.fetchurl {
    url = "https://github.com/anmonteiro/ocaml-h2/releases/download/0.12.0/h2-0.12.0.tbz";
    sha256 = "sha256-NuQLET2Q6jg2GajHvZk/hmExw8XZV2GbaEnrMq+MU8Y=";
    };
    propagatedBuildInputs = with pkgs; [
    ocamlPackages.base64
    ocamlPackages.angstrom
    ocamlPackages.faraday
    ocamlPackages.bigstringaf
    ocamlPackages.psq
    ocamlPackages.hpack
    ocamlPackages.httpun-types
    ocamlPackages.alcotest
    ocamlPackages.yojson
    ocamlPackages.hex
    ];
    };
    grpc = ocamlPackages.buildDunePackage rec {
    pname = "grpc";
    version = "0.2.0";
    src = pkgs.fetchurl {
    url = "https://github.com/dialohq/ocaml-grpc/archive/refs/tags/0.2.0.tar.gz";
    sha256 = "sha256-5myWWT3qziJ9m84aRXodGRZ5sGlUNBcY/6nkkzJ4in4=";
    };
    propagatedBuildInputs = with pkgs; [
    ocamlPackages.uri
    h2
    ocamlPackages.ppx_deriving
    ocamlPackages.ppxlib
    ];
    };
    grpc-lwt = ocamlPackages.buildDunePackage rec {
    pname = "grpc-lwt";
    version = "0.2.0";
    src = pkgs.fetchurl {
    url = "https://github.com/dialohq/ocaml-grpc/archive/refs/tags/0.2.0.tar.gz";
    sha256 = "sha256-5myWWT3qziJ9m84aRXodGRZ5sGlUNBcY/6nkkzJ4in4=";
    };
    propagatedBuildInputs = with pkgs; [
    ocamlPackages.stringext
    ocamlPackages.lwt
    grpc
    ];
    };
    elpe = ocamlPackages.buildDunePackage rec {
    pname = "elpe";
    version = "0.1.0";
    src = ./elpe;
    propagatedBuildInputs = with pkgs; [
    ocamlPackages.ocaml-protoc
    ocamlPackages.pbrt
    ocamlPackages.findlib
    ocamlPackages.ocaml-protoc-plugin
    grpc-lwt
    h2-lwt-unix
    ];
    nativeBuildInputs = [
    protobuf
    ];
    };
    in
    clangStdenv.mkDerivation {
    name = "elpe";
    buildInputs = [
    openssl nettle zstd.dev sequoia-sq
    xz.dev
    pkg-config
    # luau
    ocaml
    opam
    ocamlPackages.ocaml
    ocamlPackages.dune_3
    ocamlPackages.ocaml-protoc
    ocamlPackages.pbrt
    ocamlPackages.findlib
    ocamlPackages.ocaml-protoc-plugin
    grpc-lwt
    h2-lwt-unix
    elpe
    ocamlformat
    protobuf
    checksec
    linuxPackages_latest.perf
    ];
    nativeBuildInputs = [pkg-config b3sum];
    LIBCLANG_PATH="${llvmPackages.libclang.lib}/lib";
    PROTOC="${protobuf}/bin/protoc";
    }
  • file addition: build.rs (----------)
    [2.1]
    use std::{env, path::PathBuf};
    fn main() {
    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    tonic_build::configure()
    .file_descriptor_set_path(out_dir.join("elpe_descriptor.bin"))
    .compile_protos(&["elpe/lib/elpegrpc.proto"], &["elpe/lib"])
    .unwrap();
    }
  • file addition: Cargo.toml (----------)
    [2.1]
    [package]
    name = "elpe"
    version = "0.1.0"
    edition = "2024"
    # [profile.release]
    # debug = 1
    [workspace]
    members = ["elfedit"]
    [dependencies]
    elfedit = { path = "elfedit" }
    base32 = "0.5.1"
    blake3 = "1.6.1"
    data-encoding = "2.8.0"
    futures = "0.3.31"
    lazy_static = "1.5.0"
    libc = "*"
    memmap = "0.7.0"
    nom = "8.0.0"
    regex = "1.11.1"
    reqwest = { version = "0.12.12", features = [ "stream" ] }
    sha2 = "0.10.8"
    tar = "0.4.44"
    tempfile = "3.18.0"
    thiserror = "2.0.11"
    tokio = { version = "1.44.0", features = [ "macros", "rt-multi-thread", "fs", "process" ] }
    tracing = "0.1.41"
    tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
    xz2 = { version = "0.1.6", features = [ "tokio" ] }
    zstd = "0.13.3"
    prost = "0.13.5"
    prost-types = "0.13.5"
    tonic = "0.13.0"
    lazy-init = "0.5.1"
    lru = "0.14.0"
    [build-dependencies]
    tonic-build = "0.13.0"
  • file addition: Cargo.lock (----------)
    [2.1]
    # This file is automatically @generated by Cargo.
    # It is not intended for manual editing.
    version = 4
    [[package]]
    name = "addr2line"
    version = "0.24.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
    dependencies = [
    "gimli",
    ]
    [[package]]
    name = "adler2"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
    [[package]]
    name = "aho-corasick"
    version = "1.1.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
    dependencies = [
    "memchr",
    ]
    [[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.98"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
    [[package]]
    name = "arrayref"
    version = "0.3.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
    [[package]]
    name = "arrayvec"
    version = "0.7.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
    [[package]]
    name = "async-trait"
    version = "0.1.88"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "atomic-waker"
    version = "1.1.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
    [[package]]
    name = "autocfg"
    version = "1.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
    [[package]]
    name = "axum"
    version = "0.8.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288"
    dependencies = [
    "axum-core",
    "bytes 1.10.1",
    "futures-util",
    "http",
    "http-body",
    "http-body-util",
    "itoa",
    "matchit",
    "memchr",
    "mime",
    "percent-encoding",
    "pin-project-lite",
    "rustversion",
    "serde",
    "sync_wrapper",
    "tower",
    "tower-layer",
    "tower-service",
    ]
    [[package]]
    name = "axum-core"
    version = "0.5.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6"
    dependencies = [
    "bytes 1.10.1",
    "futures-core",
    "http",
    "http-body",
    "http-body-util",
    "mime",
    "pin-project-lite",
    "rustversion",
    "sync_wrapper",
    "tower-layer",
    "tower-service",
    ]
    [[package]]
    name = "backtrace"
    version = "0.3.74"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
    dependencies = [
    "addr2line",
    "cfg-if",
    "libc",
    "miniz_oxide",
    "object",
    "rustc-demangle",
    "windows-targets",
    ]
    [[package]]
    name = "base32"
    version = "0.5.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076"
    [[package]]
    name = "base64"
    version = "0.22.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
    [[package]]
    name = "bitflags"
    version = "2.9.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
    [[package]]
    name = "blake3"
    version = "1.6.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "675f87afced0413c9bb02843499dbbd3882a237645883f71a2b59644a6d2f753"
    dependencies = [
    "arrayref",
    "arrayvec",
    "cc",
    "cfg-if",
    "constant_time_eq",
    ]
    [[package]]
    name = "block-buffer"
    version = "0.10.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
    dependencies = [
    "generic-array",
    ]
    [[package]]
    name = "bumpalo"
    version = "3.17.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
    [[package]]
    name = "byteorder"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
    [[package]]
    name = "bytes"
    version = "0.4.12"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
    dependencies = [
    "byteorder",
    "iovec",
    ]
    [[package]]
    name = "bytes"
    version = "1.10.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
    [[package]]
    name = "cc"
    version = "1.2.16"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
    dependencies = [
    "jobserver",
    "libc",
    "shlex",
    ]
    [[package]]
    name = "cfg-if"
    version = "1.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
    [[package]]
    name = "constant_time_eq"
    version = "0.3.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
    [[package]]
    name = "core-foundation"
    version = "0.9.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
    dependencies = [
    "core-foundation-sys",
    "libc",
    ]
    [[package]]
    name = "core-foundation-sys"
    version = "0.8.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
    [[package]]
    name = "cpufeatures"
    version = "0.2.17"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
    dependencies = [
    "libc",
    ]
    [[package]]
    name = "crypto-common"
    version = "0.1.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
    dependencies = [
    "generic-array",
    "typenum",
    ]
    [[package]]
    name = "data-encoding"
    version = "2.8.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010"
    [[package]]
    name = "digest"
    version = "0.10.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
    dependencies = [
    "block-buffer",
    "crypto-common",
    ]
    [[package]]
    name = "displaydoc"
    version = "0.2.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "either"
    version = "1.15.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
    [[package]]
    name = "elfedit"
    version = "0.1.0"
    dependencies = [
    "memmap",
    "tempfile",
    "thiserror",
    ]
    [[package]]
    name = "elpe"
    version = "0.1.0"
    dependencies = [
    "base32",
    "blake3",
    "data-encoding",
    "elfedit",
    "futures 0.3.31",
    "lazy-init",
    "lazy_static",
    "libc",
    "lru",
    "memmap",
    "nom",
    "prost",
    "prost-types",
    "regex",
    "reqwest",
    "sha2",
    "tar",
    "tempfile",
    "thiserror",
    "tokio",
    "tonic",
    "tonic-build",
    "tracing",
    "tracing-subscriber",
    "xz2",
    "zstd",
    ]
    [[package]]
    name = "encoding_rs"
    version = "0.8.35"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
    dependencies = [
    "cfg-if",
    ]
    [[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.10"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
    dependencies = [
    "libc",
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "fastrand"
    version = "2.3.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
    [[package]]
    name = "filetime"
    version = "0.2.25"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
    dependencies = [
    "cfg-if",
    "libc",
    "libredox",
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "fixedbitset"
    version = "0.5.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
    [[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 = "foreign-types"
    version = "0.3.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
    dependencies = [
    "foreign-types-shared",
    ]
    [[package]]
    name = "foreign-types-shared"
    version = "0.1.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
    [[package]]
    name = "form_urlencoded"
    version = "1.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
    dependencies = [
    "percent-encoding",
    ]
    [[package]]
    name = "futures"
    version = "0.1.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
    [[package]]
    name = "futures"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
    dependencies = [
    "futures-channel",
    "futures-core",
    "futures-executor",
    "futures-io",
    "futures-sink",
    "futures-task",
    "futures-util",
    ]
    [[package]]
    name = "futures-channel"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
    dependencies = [
    "futures-core",
    "futures-sink",
    ]
    [[package]]
    name = "futures-core"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
    [[package]]
    name = "futures-executor"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
    dependencies = [
    "futures-core",
    "futures-task",
    "futures-util",
    ]
    [[package]]
    name = "futures-io"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
    [[package]]
    name = "futures-macro"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "futures-sink"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
    [[package]]
    name = "futures-task"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
    [[package]]
    name = "futures-util"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
    dependencies = [
    "futures-channel",
    "futures-core",
    "futures-io",
    "futures-macro",
    "futures-sink",
    "futures-task",
    "memchr",
    "pin-project-lite",
    "pin-utils",
    "slab",
    ]
    [[package]]
    name = "generic-array"
    version = "0.14.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
    dependencies = [
    "typenum",
    "version_check",
    ]
    [[package]]
    name = "getrandom"
    version = "0.2.15"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
    dependencies = [
    "cfg-if",
    "libc",
    "wasi 0.11.0+wasi-snapshot-preview1",
    ]
    [[package]]
    name = "getrandom"
    version = "0.3.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
    dependencies = [
    "cfg-if",
    "libc",
    "wasi 0.13.3+wasi-0.2.2",
    "windows-targets",
    ]
    [[package]]
    name = "gimli"
    version = "0.31.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
    [[package]]
    name = "h2"
    version = "0.4.8"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2"
    dependencies = [
    "atomic-waker",
    "bytes 1.10.1",
    "fnv",
    "futures-core",
    "futures-sink",
    "http",
    "indexmap",
    "slab",
    "tokio",
    "tokio-util",
    "tracing",
    ]
    [[package]]
    name = "hashbrown"
    version = "0.15.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
    dependencies = [
    "allocator-api2",
    "equivalent",
    "foldhash",
    ]
    [[package]]
    name = "heck"
    version = "0.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
    [[package]]
    name = "http"
    version = "1.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
    dependencies = [
    "bytes 1.10.1",
    "fnv",
    "itoa",
    ]
    [[package]]
    name = "http-body"
    version = "1.0.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
    dependencies = [
    "bytes 1.10.1",
    "http",
    ]
    [[package]]
    name = "http-body-util"
    version = "0.1.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
    dependencies = [
    "bytes 1.10.1",
    "futures-util",
    "http",
    "http-body",
    "pin-project-lite",
    ]
    [[package]]
    name = "httparse"
    version = "1.10.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
    [[package]]
    name = "httpdate"
    version = "1.0.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
    [[package]]
    name = "hyper"
    version = "1.6.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
    dependencies = [
    "bytes 1.10.1",
    "futures-channel",
    "futures-util",
    "h2",
    "http",
    "http-body",
    "httparse",
    "httpdate",
    "itoa",
    "pin-project-lite",
    "smallvec",
    "tokio",
    "want",
    ]
    [[package]]
    name = "hyper-rustls"
    version = "0.27.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
    dependencies = [
    "futures-util",
    "http",
    "hyper",
    "hyper-util",
    "rustls",
    "rustls-pki-types",
    "tokio",
    "tokio-rustls",
    "tower-service",
    ]
    [[package]]
    name = "hyper-timeout"
    version = "0.5.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
    dependencies = [
    "hyper",
    "hyper-util",
    "pin-project-lite",
    "tokio",
    "tower-service",
    ]
    [[package]]
    name = "hyper-tls"
    version = "0.6.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
    dependencies = [
    "bytes 1.10.1",
    "http-body-util",
    "hyper",
    "hyper-util",
    "native-tls",
    "tokio",
    "tokio-native-tls",
    "tower-service",
    ]
    [[package]]
    name = "hyper-util"
    version = "0.1.10"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
    dependencies = [
    "bytes 1.10.1",
    "futures-channel",
    "futures-util",
    "http",
    "http-body",
    "hyper",
    "pin-project-lite",
    "socket2",
    "tokio",
    "tower-service",
    "tracing",
    ]
    [[package]]
    name = "icu_collections"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
    dependencies = [
    "displaydoc",
    "yoke",
    "zerofrom",
    "zerovec",
    ]
    [[package]]
    name = "icu_locid"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
    dependencies = [
    "displaydoc",
    "litemap",
    "tinystr",
    "writeable",
    "zerovec",
    ]
    [[package]]
    name = "icu_locid_transform"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
    dependencies = [
    "displaydoc",
    "icu_locid",
    "icu_locid_transform_data",
    "icu_provider",
    "tinystr",
    "zerovec",
    ]
    [[package]]
    name = "icu_locid_transform_data"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
    [[package]]
    name = "icu_normalizer"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
    dependencies = [
    "displaydoc",
    "icu_collections",
    "icu_normalizer_data",
    "icu_properties",
    "icu_provider",
    "smallvec",
    "utf16_iter",
    "utf8_iter",
    "write16",
    "zerovec",
    ]
    [[package]]
    name = "icu_normalizer_data"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
    [[package]]
    name = "icu_properties"
    version = "1.5.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
    dependencies = [
    "displaydoc",
    "icu_collections",
    "icu_locid_transform",
    "icu_properties_data",
    "icu_provider",
    "tinystr",
    "zerovec",
    ]
    [[package]]
    name = "icu_properties_data"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
    [[package]]
    name = "icu_provider"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
    dependencies = [
    "displaydoc",
    "icu_locid",
    "icu_provider_macros",
    "stable_deref_trait",
    "tinystr",
    "writeable",
    "yoke",
    "zerofrom",
    "zerovec",
    ]
    [[package]]
    name = "icu_provider_macros"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "idna"
    version = "1.0.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
    dependencies = [
    "idna_adapter",
    "smallvec",
    "utf8_iter",
    ]
    [[package]]
    name = "idna_adapter"
    version = "1.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
    dependencies = [
    "icu_normalizer",
    "icu_properties",
    ]
    [[package]]
    name = "indexmap"
    version = "2.7.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
    dependencies = [
    "equivalent",
    "hashbrown",
    ]
    [[package]]
    name = "iovec"
    version = "0.1.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
    dependencies = [
    "libc",
    ]
    [[package]]
    name = "ipnet"
    version = "2.11.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
    [[package]]
    name = "itertools"
    version = "0.14.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
    dependencies = [
    "either",
    ]
    [[package]]
    name = "itoa"
    version = "1.0.15"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
    [[package]]
    name = "jobserver"
    version = "0.1.32"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
    dependencies = [
    "libc",
    ]
    [[package]]
    name = "js-sys"
    version = "0.3.77"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
    dependencies = [
    "once_cell",
    "wasm-bindgen",
    ]
    [[package]]
    name = "lazy-init"
    version = "0.5.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9f40963626ac12dcaf92afc15e4c3db624858c92fd9f8ba2125eaada3ac2706f"
    [[package]]
    name = "lazy_static"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
    [[package]]
    name = "libc"
    version = "0.2.171"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
    [[package]]
    name = "libredox"
    version = "0.1.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
    dependencies = [
    "bitflags",
    "libc",
    "redox_syscall",
    ]
    [[package]]
    name = "linux-raw-sys"
    version = "0.4.15"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
    [[package]]
    name = "linux-raw-sys"
    version = "0.9.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9"
    [[package]]
    name = "litemap"
    version = "0.7.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
    [[package]]
    name = "log"
    version = "0.4.26"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
    [[package]]
    name = "lru"
    version = "0.14.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198"
    dependencies = [
    "hashbrown",
    ]
    [[package]]
    name = "lzma-sys"
    version = "0.1.20"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
    dependencies = [
    "cc",
    "libc",
    "pkg-config",
    ]
    [[package]]
    name = "matchers"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
    dependencies = [
    "regex-automata 0.1.10",
    ]
    [[package]]
    name = "matchit"
    version = "0.8.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
    [[package]]
    name = "memchr"
    version = "2.7.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
    [[package]]
    name = "memmap"
    version = "0.7.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
    dependencies = [
    "libc",
    "winapi",
    ]
    [[package]]
    name = "mime"
    version = "0.3.17"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
    [[package]]
    name = "miniz_oxide"
    version = "0.8.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
    dependencies = [
    "adler2",
    ]
    [[package]]
    name = "mio"
    version = "1.0.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
    dependencies = [
    "libc",
    "wasi 0.11.0+wasi-snapshot-preview1",
    "windows-sys 0.52.0",
    ]
    [[package]]
    name = "multimap"
    version = "0.10.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
    [[package]]
    name = "native-tls"
    version = "0.2.14"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
    dependencies = [
    "libc",
    "log",
    "openssl",
    "openssl-probe",
    "openssl-sys",
    "schannel",
    "security-framework",
    "security-framework-sys",
    "tempfile",
    ]
    [[package]]
    name = "nom"
    version = "8.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
    dependencies = [
    "memchr",
    ]
    [[package]]
    name = "nu-ansi-term"
    version = "0.46.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
    dependencies = [
    "overload",
    "winapi",
    ]
    [[package]]
    name = "object"
    version = "0.36.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
    dependencies = [
    "memchr",
    ]
    [[package]]
    name = "once_cell"
    version = "1.21.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad"
    [[package]]
    name = "openssl"
    version = "0.10.71"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
    dependencies = [
    "bitflags",
    "cfg-if",
    "foreign-types",
    "libc",
    "once_cell",
    "openssl-macros",
    "openssl-sys",
    ]
    [[package]]
    name = "openssl-macros"
    version = "0.1.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "openssl-probe"
    version = "0.1.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
    [[package]]
    name = "openssl-sys"
    version = "0.9.106"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
    dependencies = [
    "cc",
    "libc",
    "pkg-config",
    "vcpkg",
    ]
    [[package]]
    name = "overload"
    version = "0.1.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
    [[package]]
    name = "percent-encoding"
    version = "2.3.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
    [[package]]
    name = "petgraph"
    version = "0.7.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
    dependencies = [
    "fixedbitset",
    "indexmap",
    ]
    [[package]]
    name = "pin-project"
    version = "1.1.10"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
    dependencies = [
    "pin-project-internal",
    ]
    [[package]]
    name = "pin-project-internal"
    version = "1.1.10"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "pin-project-lite"
    version = "0.2.16"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
    [[package]]
    name = "pin-utils"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
    [[package]]
    name = "pkg-config"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
    [[package]]
    name = "prettyplease"
    version = "0.2.32"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6"
    dependencies = [
    "proc-macro2",
    "syn",
    ]
    [[package]]
    name = "proc-macro2"
    version = "1.0.93"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
    dependencies = [
    "unicode-ident",
    ]
    [[package]]
    name = "prost"
    version = "0.13.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5"
    dependencies = [
    "bytes 1.10.1",
    "prost-derive",
    ]
    [[package]]
    name = "prost-build"
    version = "0.13.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
    dependencies = [
    "heck",
    "itertools",
    "log",
    "multimap",
    "once_cell",
    "petgraph",
    "prettyplease",
    "prost",
    "prost-types",
    "regex",
    "syn",
    "tempfile",
    ]
    [[package]]
    name = "prost-derive"
    version = "0.13.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
    dependencies = [
    "anyhow",
    "itertools",
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "prost-types"
    version = "0.13.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16"
    dependencies = [
    "prost",
    ]
    [[package]]
    name = "quote"
    version = "1.0.38"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
    dependencies = [
    "proc-macro2",
    ]
    [[package]]
    name = "redox_syscall"
    version = "0.5.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f"
    dependencies = [
    "bitflags",
    ]
    [[package]]
    name = "regex"
    version = "1.11.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
    dependencies = [
    "aho-corasick",
    "memchr",
    "regex-automata 0.4.9",
    "regex-syntax 0.8.5",
    ]
    [[package]]
    name = "regex-automata"
    version = "0.1.10"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
    dependencies = [
    "regex-syntax 0.6.29",
    ]
    [[package]]
    name = "regex-automata"
    version = "0.4.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
    dependencies = [
    "aho-corasick",
    "memchr",
    "regex-syntax 0.8.5",
    ]
    [[package]]
    name = "regex-syntax"
    version = "0.6.29"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
    [[package]]
    name = "regex-syntax"
    version = "0.8.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
    [[package]]
    name = "reqwest"
    version = "0.12.12"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da"
    dependencies = [
    "base64",
    "bytes 1.10.1",
    "encoding_rs",
    "futures-core",
    "futures-util",
    "h2",
    "http",
    "http-body",
    "http-body-util",
    "hyper",
    "hyper-rustls",
    "hyper-tls",
    "hyper-util",
    "ipnet",
    "js-sys",
    "log",
    "mime",
    "native-tls",
    "once_cell",
    "percent-encoding",
    "pin-project-lite",
    "rustls-pemfile",
    "serde",
    "serde_json",
    "serde_urlencoded",
    "sync_wrapper",
    "system-configuration",
    "tokio",
    "tokio-native-tls",
    "tokio-util",
    "tower",
    "tower-service",
    "url",
    "wasm-bindgen",
    "wasm-bindgen-futures",
    "wasm-streams",
    "web-sys",
    "windows-registry",
    ]
    [[package]]
    name = "ring"
    version = "0.17.13"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee"
    dependencies = [
    "cc",
    "cfg-if",
    "getrandom 0.2.15",
    "libc",
    "untrusted",
    "windows-sys 0.52.0",
    ]
    [[package]]
    name = "rustc-demangle"
    version = "0.1.24"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
    [[package]]
    name = "rustix"
    version = "0.38.44"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
    dependencies = [
    "bitflags",
    "errno",
    "libc",
    "linux-raw-sys 0.4.15",
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "rustix"
    version = "1.0.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825"
    dependencies = [
    "bitflags",
    "errno",
    "libc",
    "linux-raw-sys 0.9.2",
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "rustls"
    version = "0.23.23"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395"
    dependencies = [
    "once_cell",
    "rustls-pki-types",
    "rustls-webpki",
    "subtle",
    "zeroize",
    ]
    [[package]]
    name = "rustls-pemfile"
    version = "2.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
    dependencies = [
    "rustls-pki-types",
    ]
    [[package]]
    name = "rustls-pki-types"
    version = "1.11.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
    [[package]]
    name = "rustls-webpki"
    version = "0.102.8"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
    dependencies = [
    "ring",
    "rustls-pki-types",
    "untrusted",
    ]
    [[package]]
    name = "rustversion"
    version = "1.0.20"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
    [[package]]
    name = "ryu"
    version = "1.0.20"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
    [[package]]
    name = "schannel"
    version = "0.1.27"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
    dependencies = [
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "security-framework"
    version = "2.11.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
    dependencies = [
    "bitflags",
    "core-foundation",
    "core-foundation-sys",
    "libc",
    "security-framework-sys",
    ]
    [[package]]
    name = "security-framework-sys"
    version = "2.14.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
    dependencies = [
    "core-foundation-sys",
    "libc",
    ]
    [[package]]
    name = "serde"
    version = "1.0.219"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
    dependencies = [
    "serde_derive",
    ]
    [[package]]
    name = "serde_derive"
    version = "1.0.219"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "serde_json"
    version = "1.0.140"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
    dependencies = [
    "itoa",
    "memchr",
    "ryu",
    "serde",
    ]
    [[package]]
    name = "serde_urlencoded"
    version = "0.7.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
    dependencies = [
    "form_urlencoded",
    "itoa",
    "ryu",
    "serde",
    ]
    [[package]]
    name = "sha2"
    version = "0.10.8"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
    dependencies = [
    "cfg-if",
    "cpufeatures",
    "digest",
    ]
    [[package]]
    name = "sharded-slab"
    version = "0.1.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
    dependencies = [
    "lazy_static",
    ]
    [[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.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
    dependencies = [
    "libc",
    ]
    [[package]]
    name = "slab"
    version = "0.4.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
    dependencies = [
    "autocfg",
    ]
    [[package]]
    name = "smallvec"
    version = "1.14.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
    [[package]]
    name = "socket2"
    version = "0.5.8"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
    dependencies = [
    "libc",
    "windows-sys 0.52.0",
    ]
    [[package]]
    name = "stable_deref_trait"
    version = "1.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
    [[package]]
    name = "subtle"
    version = "2.6.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
    [[package]]
    name = "syn"
    version = "2.0.98"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
    dependencies = [
    "proc-macro2",
    "quote",
    "unicode-ident",
    ]
    [[package]]
    name = "sync_wrapper"
    version = "1.0.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
    dependencies = [
    "futures-core",
    ]
    [[package]]
    name = "synstructure"
    version = "0.13.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "system-configuration"
    version = "0.6.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
    dependencies = [
    "bitflags",
    "core-foundation",
    "system-configuration-sys",
    ]
    [[package]]
    name = "system-configuration-sys"
    version = "0.6.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
    dependencies = [
    "core-foundation-sys",
    "libc",
    ]
    [[package]]
    name = "tar"
    version = "0.4.44"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
    dependencies = [
    "filetime",
    "libc",
    "xattr",
    ]
    [[package]]
    name = "tempfile"
    version = "3.19.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
    dependencies = [
    "fastrand",
    "getrandom 0.3.1",
    "once_cell",
    "rustix 1.0.2",
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "thiserror"
    version = "2.0.12"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
    dependencies = [
    "thiserror-impl",
    ]
    [[package]]
    name = "thiserror-impl"
    version = "2.0.12"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "thread_local"
    version = "1.1.8"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
    dependencies = [
    "cfg-if",
    "once_cell",
    ]
    [[package]]
    name = "tinystr"
    version = "0.7.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
    dependencies = [
    "displaydoc",
    "zerovec",
    ]
    [[package]]
    name = "tokio"
    version = "1.44.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a"
    dependencies = [
    "backtrace",
    "bytes 1.10.1",
    "libc",
    "mio",
    "pin-project-lite",
    "signal-hook-registry",
    "socket2",
    "tokio-macros",
    "windows-sys 0.52.0",
    ]
    [[package]]
    name = "tokio-io"
    version = "0.1.13"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674"
    dependencies = [
    "bytes 0.4.12",
    "futures 0.1.31",
    "log",
    ]
    [[package]]
    name = "tokio-macros"
    version = "2.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "tokio-native-tls"
    version = "0.3.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
    dependencies = [
    "native-tls",
    "tokio",
    ]
    [[package]]
    name = "tokio-rustls"
    version = "0.26.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
    dependencies = [
    "rustls",
    "tokio",
    ]
    [[package]]
    name = "tokio-stream"
    version = "0.1.17"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
    dependencies = [
    "futures-core",
    "pin-project-lite",
    "tokio",
    ]
    [[package]]
    name = "tokio-util"
    version = "0.7.13"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
    dependencies = [
    "bytes 1.10.1",
    "futures-core",
    "futures-sink",
    "pin-project-lite",
    "tokio",
    ]
    [[package]]
    name = "tonic"
    version = "0.13.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "85839f0b32fd242bb3209262371d07feda6d780d16ee9d2bc88581b89da1549b"
    dependencies = [
    "async-trait",
    "axum",
    "base64",
    "bytes 1.10.1",
    "h2",
    "http",
    "http-body",
    "http-body-util",
    "hyper",
    "hyper-timeout",
    "hyper-util",
    "percent-encoding",
    "pin-project",
    "prost",
    "socket2",
    "tokio",
    "tokio-stream",
    "tower",
    "tower-layer",
    "tower-service",
    "tracing",
    ]
    [[package]]
    name = "tonic-build"
    version = "0.13.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d85f0383fadd15609306383a90e85eaed44169f931a5d2be1b42c76ceff1825e"
    dependencies = [
    "prettyplease",
    "proc-macro2",
    "prost-build",
    "prost-types",
    "quote",
    "syn",
    ]
    [[package]]
    name = "tower"
    version = "0.5.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
    dependencies = [
    "futures-core",
    "futures-util",
    "indexmap",
    "pin-project-lite",
    "slab",
    "sync_wrapper",
    "tokio",
    "tokio-util",
    "tower-layer",
    "tower-service",
    "tracing",
    ]
    [[package]]
    name = "tower-layer"
    version = "0.3.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
    [[package]]
    name = "tower-service"
    version = "0.3.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
    [[package]]
    name = "tracing"
    version = "0.1.41"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
    dependencies = [
    "pin-project-lite",
    "tracing-attributes",
    "tracing-core",
    ]
    [[package]]
    name = "tracing-attributes"
    version = "0.1.28"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "tracing-core"
    version = "0.1.33"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
    dependencies = [
    "once_cell",
    "valuable",
    ]
    [[package]]
    name = "tracing-log"
    version = "0.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
    dependencies = [
    "log",
    "once_cell",
    "tracing-core",
    ]
    [[package]]
    name = "tracing-subscriber"
    version = "0.3.19"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
    dependencies = [
    "matchers",
    "nu-ansi-term",
    "once_cell",
    "regex",
    "sharded-slab",
    "smallvec",
    "thread_local",
    "tracing",
    "tracing-core",
    "tracing-log",
    ]
    [[package]]
    name = "try-lock"
    version = "0.2.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
    [[package]]
    name = "typenum"
    version = "1.18.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
    [[package]]
    name = "unicode-ident"
    version = "1.0.17"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
    [[package]]
    name = "untrusted"
    version = "0.9.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
    [[package]]
    name = "url"
    version = "2.5.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
    dependencies = [
    "form_urlencoded",
    "idna",
    "percent-encoding",
    ]
    [[package]]
    name = "utf16_iter"
    version = "1.0.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
    [[package]]
    name = "utf8_iter"
    version = "1.0.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
    [[package]]
    name = "valuable"
    version = "0.1.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
    [[package]]
    name = "vcpkg"
    version = "0.2.15"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
    [[package]]
    name = "version_check"
    version = "0.9.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
    [[package]]
    name = "want"
    version = "0.3.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
    dependencies = [
    "try-lock",
    ]
    [[package]]
    name = "wasi"
    version = "0.11.0+wasi-snapshot-preview1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
    [[package]]
    name = "wasi"
    version = "0.13.3+wasi-0.2.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
    dependencies = [
    "wit-bindgen-rt",
    ]
    [[package]]
    name = "wasm-bindgen"
    version = "0.2.100"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
    dependencies = [
    "cfg-if",
    "once_cell",
    "rustversion",
    "wasm-bindgen-macro",
    ]
    [[package]]
    name = "wasm-bindgen-backend"
    version = "0.2.100"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
    dependencies = [
    "bumpalo",
    "log",
    "proc-macro2",
    "quote",
    "syn",
    "wasm-bindgen-shared",
    ]
    [[package]]
    name = "wasm-bindgen-futures"
    version = "0.4.50"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
    dependencies = [
    "cfg-if",
    "js-sys",
    "once_cell",
    "wasm-bindgen",
    "web-sys",
    ]
    [[package]]
    name = "wasm-bindgen-macro"
    version = "0.2.100"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
    dependencies = [
    "quote",
    "wasm-bindgen-macro-support",
    ]
    [[package]]
    name = "wasm-bindgen-macro-support"
    version = "0.2.100"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    "wasm-bindgen-backend",
    "wasm-bindgen-shared",
    ]
    [[package]]
    name = "wasm-bindgen-shared"
    version = "0.2.100"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
    dependencies = [
    "unicode-ident",
    ]
    [[package]]
    name = "wasm-streams"
    version = "0.4.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
    dependencies = [
    "futures-util",
    "js-sys",
    "wasm-bindgen",
    "wasm-bindgen-futures",
    "web-sys",
    ]
    [[package]]
    name = "web-sys"
    version = "0.3.77"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
    dependencies = [
    "js-sys",
    "wasm-bindgen",
    ]
    [[package]]
    name = "winapi"
    version = "0.3.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
    dependencies = [
    "winapi-i686-pc-windows-gnu",
    "winapi-x86_64-pc-windows-gnu",
    ]
    [[package]]
    name = "winapi-i686-pc-windows-gnu"
    version = "0.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
    [[package]]
    name = "winapi-x86_64-pc-windows-gnu"
    version = "0.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
    [[package]]
    name = "windows-registry"
    version = "0.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
    dependencies = [
    "windows-result",
    "windows-strings",
    "windows-targets",
    ]
    [[package]]
    name = "windows-result"
    version = "0.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
    dependencies = [
    "windows-targets",
    ]
    [[package]]
    name = "windows-strings"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
    dependencies = [
    "windows-result",
    "windows-targets",
    ]
    [[package]]
    name = "windows-sys"
    version = "0.52.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
    dependencies = [
    "windows-targets",
    ]
    [[package]]
    name = "windows-sys"
    version = "0.59.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
    dependencies = [
    "windows-targets",
    ]
    [[package]]
    name = "windows-targets"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
    dependencies = [
    "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.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
    [[package]]
    name = "windows_aarch64_msvc"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
    [[package]]
    name = "windows_i686_gnu"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
    [[package]]
    name = "windows_i686_gnullvm"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
    [[package]]
    name = "windows_i686_msvc"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
    [[package]]
    name = "windows_x86_64_gnu"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
    [[package]]
    name = "windows_x86_64_gnullvm"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
    [[package]]
    name = "windows_x86_64_msvc"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
    [[package]]
    name = "wit-bindgen-rt"
    version = "0.33.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
    dependencies = [
    "bitflags",
    ]
    [[package]]
    name = "write16"
    version = "1.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
    [[package]]
    name = "writeable"
    version = "0.5.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
    [[package]]
    name = "xattr"
    version = "1.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909"
    dependencies = [
    "libc",
    "linux-raw-sys 0.4.15",
    "rustix 0.38.44",
    ]
    [[package]]
    name = "xz2"
    version = "0.1.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
    dependencies = [
    "futures 0.1.31",
    "lzma-sys",
    "tokio-io",
    ]
    [[package]]
    name = "yoke"
    version = "0.7.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
    dependencies = [
    "serde",
    "stable_deref_trait",
    "yoke-derive",
    "zerofrom",
    ]
    [[package]]
    name = "yoke-derive"
    version = "0.7.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    "synstructure",
    ]
    [[package]]
    name = "zerofrom"
    version = "0.1.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
    dependencies = [
    "zerofrom-derive",
    ]
    [[package]]
    name = "zerofrom-derive"
    version = "0.1.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    "synstructure",
    ]
    [[package]]
    name = "zeroize"
    version = "1.8.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
    [[package]]
    name = "zerovec"
    version = "0.10.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
    dependencies = [
    "yoke",
    "zerofrom",
    "zerovec-derive",
    ]
    [[package]]
    name = "zerovec-derive"
    version = "0.10.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "zstd"
    version = "0.13.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
    dependencies = [
    "zstd-safe",
    ]
    [[package]]
    name = "zstd-safe"
    version = "7.2.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722"
    dependencies = [
    "zstd-sys",
    ]
    [[package]]
    name = "zstd-sys"
    version = "2.0.14+zstd.1.5.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8fb060d4926e4ac3a3ad15d864e99ceb5f343c6b34f5bd6d81ae6ed417311be5"
    dependencies = [
    "cc",
    "pkg-config",
    ]