├── .gitignore ├── src ├── no_face.png ├── actions.rs ├── main.rs ├── tools.rs ├── deasterisk.rs ├── tavern_card_v2.rs └── baya_download.rs ├── rustfmt.toml ├── LICENSE.md ├── Cargo.toml ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.vscode 3 | *.log 4 | src/example.rs 5 | testing/* 6 | -------------------------------------------------------------------------------- /src/no_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Barafu/tavern_card_tools/HEAD/src/no_face.png -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | control_brace_style = "ClosingNextLine" 2 | fn_single_line = true 3 | max_width = 80 4 | imports_granularity = "Module" 5 | reorder_impl_items = true 6 | group_imports = "StdExternalCrate" 7 | use_small_heuristics = "Max" -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Barafu Albino 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tavern_card_tools" 3 | version = "0.1.4" 4 | edition = "2021" 5 | authors = ["Barafu Albino "] 6 | 7 | [profile.release] 8 | strip = true #Remove extra symbols 9 | opt-level = "s" #Optimize for size 10 | lto = true #Enable linker optimizations 11 | codegen-units=1 #Maximise optimizations 12 | 13 | [dependencies] 14 | anyhow = "1.0.86" 15 | base64 = "0.22.1" 16 | bytes = { version = "1.6.0", features = ["serde"] } 17 | chrono = { version = "0.4.38", features = ["serde"] } 18 | clap = { version = "4.5.9", features = ["derive", "unicode"] } 19 | env_logger = "0.11.3" 20 | image = {version = "0.25.1", features = ["png", "bmp", "gif", "hdr", "ico", "jpeg", "webp"], default-features = false} 21 | log = { version = "0.4.22", features = ["serde"] } 22 | png = "0.17.13" 23 | reqwest = { version = "0.12.5", features = ["blocking"] } 24 | serde = { version = "1.0.204", features = ["derive"] } 25 | serde-transcode = "1.1.1" 26 | serde_json = "1.0.120" 27 | serde_path_to_error = "0.1.16" 28 | soup = "0.5.1" 29 | test-context = "0.3.0" 30 | textwrap = { version = "0.16.1", features = ["terminal_size"] } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tools for working with SillyTavern cards 2 | 3 | ## Currently supported functions: 4 | 5 | * `tavern_card_tools.exe print ` - print the meaningfull content of the character data to the terminal. 6 | * `tavern_card_tools.exe ` - same as above, print the character data. 7 | * `tavern_card_tools.exe print_all ` - print all character data as JSON to the terminal. 8 | * `tavern_card_tools.exe baya_get ` - extract a character card from "Backyard AI" URL. Supports URLs that require registration. Will automatically convert all instances of word `User` into `{{user}}` 9 | * `tavern_card_tools.exe de8 ` - remove paired asterisks from all primary text fields of the card. Creates a new file for the output, named de8.filename.png, and leaves original as it is. 10 | Add `--force` flag to overwrite output file even if it already exists. 11 | 12 | 13 | Obviously, more functions planned in the future. 14 | 15 | ## Installation 16 | 17 | Windows folks - download .EXE from [releases](https://github.com/Barafu/tavern_card_tools/releases/latest). No need to install, should just work. 18 | 19 | Linux crowd - you better build it from source. Download this repository. Install `cargo` and `rustc` packages. 20 | Type `cargo build --release` in the root folder of the repo. It will download dependencies and build. Here is your app in `target/release` folder. 21 | -------------------------------------------------------------------------------- /src/actions.rs: -------------------------------------------------------------------------------- 1 | //! Actions that don't fit other modules. 2 | 3 | use std::path::Path; 4 | 5 | use anyhow::Result; 6 | use base64::prelude::*; 7 | use textwrap::{fill, Options}; 8 | 9 | use crate::tavern_card_v2::{TavernCardV2, TEXT_KEY_PNG}; 10 | use crate::tools; 11 | 12 | /// Prints the content of tavern card from a given file path 13 | pub fn print_tavern_card_from_path(path: &Path) -> Result<()> { 14 | let image = tools::read_image_from_file(path)?; 15 | let card = TavernCardV2::from_png_image(&image)?; 16 | println!("{}", card); 17 | 18 | Ok(()) 19 | } 20 | 21 | /// Prints the JSON of the tavern card from path 22 | pub fn print_json_from_path(path: &Path) -> Result<()> { 23 | let image = tools::read_image_from_file(path)?; 24 | let tag = tools::read_text_chunk(&image, TEXT_KEY_PNG)?; 25 | let tag = tag.map(|x| BASE64_STANDARD.decode(x).unwrap_or_default()); 26 | let text = tag.map(|x| String::from_utf8_lossy(&x).to_string()); 27 | let mut text = text.unwrap_or_else(|| "NO TEXT".to_string()); 28 | let options = Options::new(textwrap::termwidth()); 29 | text = pretty_json(&text)?; 30 | text = fill(&text, options); 31 | println!("{}", text); 32 | Ok(()) 33 | } 34 | 35 | fn pretty_json(text: &str) -> Result { 36 | // A JSON deserializer. You can use any Serde Deserializer here. 37 | let mut deserializer = serde_json::Deserializer::from_str(text); 38 | 39 | // A compacted JSON serializer. You can use any Serde Serializer here. 40 | let mut buf: Vec = Vec::new(); 41 | let formatter = serde_json::ser::PrettyFormatter::with_indent(b" "); 42 | let mut serializer = 43 | serde_json::Serializer::with_formatter(&mut buf, formatter); 44 | 45 | serde_transcode::transcode(&mut deserializer, &mut serializer)?; 46 | 47 | Ok(String::from_utf8_lossy(&buf).to_string()) 48 | } 49 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use anyhow::Result; 4 | use clap::{Parser, ValueHint}; 5 | use std::path::{Path, PathBuf}; 6 | 7 | mod actions; 8 | mod baya_download; 9 | mod deasterisk; 10 | mod tavern_card_v2; 11 | mod tools; 12 | //mod example; 13 | 14 | const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); 15 | 16 | #[derive(Parser, Debug)] 17 | #[command(author = "Barafu Albino , 25 | 26 | /// If no command is provided, "print" command is used by default. 27 | card_path: Option, 28 | } 29 | 30 | #[derive(Parser, Debug)] 31 | enum Commands { 32 | /// Download tavern card from BackyardAI 33 | #[command(name = "baya_get")] 34 | #[command(arg_required_else_help = true)] 35 | BayaGet { 36 | /// URL at Backyard AI website to download from 37 | #[arg()] 38 | url: String, 39 | }, 40 | /// Remove paired asterisks from text in tavern card. Makes a copy of the image and renames it to de8. 41 | #[command(arg_required_else_help = true)] 42 | De8 { 43 | /// Path to image.png 44 | #[arg(value_hint = ValueHint::FilePath)] 45 | path: PathBuf, 46 | 47 | /// Overwrite output file if it exists already 48 | #[arg(long)] 49 | force: bool, 50 | }, 51 | /// Print the content of the card 52 | #[command(arg_required_else_help = true)] 53 | Print { 54 | /// Path to image.png 55 | #[arg(value_hint = ValueHint::FilePath)] 56 | path: PathBuf, 57 | }, 58 | /// Print the JSON of the card 59 | #[command(name = "print_all")] 60 | #[command(arg_required_else_help = true)] 61 | PrintJson { 62 | /// Path to image.png 63 | #[arg(value_hint = ValueHint::FilePath)] 64 | path: PathBuf, 65 | }, 66 | } 67 | 68 | fn main() { 69 | // Prepare debug logging. 70 | #[cfg(debug_assertions)] 71 | { 72 | use env_logger::Builder; 73 | use std::fs::File; 74 | let target = Box::new( 75 | File::create("testing/last_run.log").expect("Can't create file"), 76 | ); 77 | 78 | Builder::new() 79 | .target(env_logger::Target::Pipe(target)) 80 | .filter(None, log::LevelFilter::Info) 81 | .init(); 82 | } 83 | 84 | // Print intro 85 | println!("tavern card tools v{}", APP_VERSION); 86 | 87 | if let Err(err) = parse_args() { 88 | println!("Error: {}", err); 89 | std::process::exit(1); 90 | } 91 | } 92 | 93 | fn parse_args() -> Result<()> { 94 | let args = Cli::parse(); 95 | 96 | if args.card_path.is_none() && args.command.is_none() { 97 | eprintln!("Error: No command given"); 98 | // println!("{}", Cli::); 99 | std::process::exit(1); 100 | } 101 | 102 | if let Some(card_path) = args.card_path { 103 | actions::print_tavern_card_from_path(Path::new(&card_path))?; 104 | return Ok(()); 105 | } 106 | 107 | match args.command.unwrap() { 108 | Commands::BayaGet { url } => { 109 | baya_download::download_card_from_baya_url(&url)? 110 | } 111 | Commands::De8 { path, force } => { 112 | deasterisk::deasterisk_tavern_file(&path, force)? 113 | } 114 | Commands::Print { path } => { 115 | actions::print_tavern_card_from_path(&path)? 116 | } 117 | Commands::PrintJson { path } => actions::print_json_from_path(&path)?, 118 | }; 119 | Ok(()) 120 | } 121 | -------------------------------------------------------------------------------- /src/tools.rs: -------------------------------------------------------------------------------- 1 | //! Functions that will likely be useful for multiple tasks 2 | use anyhow::{bail, Context, Result}; 3 | use bytes::Bytes; 4 | use png::text_metadata::TEXtChunk; 5 | use std::path::Path; 6 | 7 | /// Download web page by URL, return contents 8 | pub fn download_page(url: &str) -> Result { 9 | let response = reqwest::blocking::get(url)?; 10 | if response.status().is_success() { 11 | let body = response.text()?; 12 | return Ok(body); 13 | } else { 14 | bail!("Failed to download the web page: {:?}", response.status()); 15 | } 16 | } 17 | 18 | /// Download image from URL. 19 | pub fn download_image(url: &str) -> Result { 20 | let downloaded_data; 21 | // Try to download the image. 22 | let response = reqwest::blocking::get(url) 23 | .context("No response when downloading image!")?; 24 | if response.status().is_success() { 25 | downloaded_data = 26 | response.bytes().context("Could not read the downloaded data.")?; 27 | } else { 28 | bail!("Could not download image: status {:?}", response.status()); 29 | }; 30 | 31 | // Convert to PNG if it's not already. 32 | let downloaded_image = convert_to_png(&downloaded_data) 33 | .context("Could not convert image to PNG")?; 34 | Ok(downloaded_image) 35 | } 36 | 37 | pub fn write_image_to_file( 38 | image_data: &Bytes, 39 | image_path: &Path, 40 | ) -> Result<()> { 41 | let mut file = std::fs::File::create(image_path)?; 42 | std::io::Write::write_all(&mut file, &image_data)?; 43 | Ok(()) 44 | } 45 | 46 | pub fn read_image_from_file(image_path: &Path) -> Result { 47 | let image_data = std::fs::read(image_path)?; 48 | Ok(Bytes::from(image_data)) 49 | } 50 | 51 | /// Convert an image to PNG format. 52 | /// 53 | /// Take an image in any supported format and convert it to PNG. 54 | /// If the input image is already in PNG format, return the original data. 55 | pub fn convert_to_png(image_data: &Bytes) -> Result { 56 | // Try to determine the format of the input image 57 | let format = image::guess_format(image_data.as_ref())?; 58 | // If it's already a PNG, return the original data 59 | if format == image::ImageFormat::Png { 60 | return Ok(image_data.clone()); 61 | } 62 | // If it's not a PNG, decode the image 63 | let img = image::load_from_memory(image_data.as_ref())?; 64 | // Prepare a buffer to store the PNG output 65 | let mut png_buffer = Vec::new(); 66 | // Convert the image to PNG and write it to the buffer 67 | img.write_to( 68 | &mut std::io::Cursor::new(&mut png_buffer), 69 | image::ImageFormat::Png, 70 | )?; 71 | let png_output: Bytes = Bytes::from(png_buffer); 72 | Ok(png_output) 73 | } 74 | 75 | /// Return the default image (in PNG format) 76 | pub fn get_default_image() -> Bytes { 77 | Bytes::from_static(include_bytes!("no_face.png")) 78 | } 79 | 80 | /// Adds a key-value tEXt chunk to PNG. 81 | /// 82 | /// Returns error if the data is not a proper PNG. Makes sure not to duplicate 83 | /// the text chunk with the same key. 84 | pub fn write_text_to_png( 85 | key: &str, 86 | value: &str, 87 | image_data: &Bytes, 88 | ) -> Result { 89 | // # Decode 90 | // The decoder is a build for reader and can be used to set various decoding options 91 | // via `Transformations`. The default output transformation is `Transformations::IDENTITY`. 92 | let decoder = png::Decoder::new(image_data.as_ref()); 93 | let mut reader = decoder.read_info()?; 94 | let png_info = reader.info().clone(); 95 | 96 | // # Encode 97 | // let path_out = image_path.with_file_name("output2"); 98 | let mut output_vec: Vec = Vec::new(); 99 | 100 | // Get defaults for interlaced parameter. 101 | let mut info_out = png_info.clone(); 102 | let info_default = png::Info::default(); 103 | info_out.interlaced = info_default.interlaced; 104 | 105 | // Add text entry. Make sure only one text entry with that key exists. 106 | info_out 107 | .uncompressed_latin1_text 108 | .retain(|x| x.keyword.to_lowercase() != key.to_lowercase()); 109 | let new_text_entry = 110 | TEXtChunk { keyword: key.to_string(), text: value.to_string() }; 111 | info_out.uncompressed_latin1_text.push(new_text_entry); 112 | 113 | let mut encoder = png::Encoder::with_info(&mut output_vec, info_out)?; 114 | encoder.set_depth(png_info.bit_depth); 115 | 116 | // Save picture with changed info. Copy frames from reader. 117 | let mut writer = encoder.write_header()?; 118 | let mut buf = vec![0; reader.output_buffer_size()]; 119 | while let Ok(info) = reader.next_frame(&mut buf) { 120 | let frame_bytes = &buf[..info.buffer_size()]; 121 | writer.write_image_data(&frame_bytes)?; 122 | } 123 | drop(buf); 124 | drop(writer); 125 | Ok(Bytes::from(output_vec)) 126 | } 127 | 128 | /// Searches PNG image for a tEXt chunk with a given key 129 | pub fn read_text_chunk( 130 | image_data: &Bytes, 131 | chunk_key: &str, 132 | ) -> Result> { 133 | // Create a decoder 134 | let decoder = png::Decoder::new(image_data.as_ref()); 135 | let mut reader = decoder.read_info()?; 136 | reader.finish()?; 137 | let png_info = reader.info(); 138 | 139 | for text_chunk in &png_info.uncompressed_latin1_text { 140 | if text_chunk.keyword.to_lowercase() == chunk_key.to_lowercase() { 141 | return Ok(Some(text_chunk.text.clone())); 142 | } 143 | } 144 | // If we didn't find the chunk, return None 145 | Ok(None) 146 | } 147 | -------------------------------------------------------------------------------- /src/deasterisk.rs: -------------------------------------------------------------------------------- 1 | //! Functions to remove asterisks. 2 | 3 | use std::path::Path; 4 | 5 | use anyhow::{bail, Result}; 6 | use log::info; 7 | 8 | use crate::{ 9 | tavern_card_v2::TavernCardV2, 10 | tools::{self, read_image_from_file}, 11 | }; 12 | 13 | /// Remove asterisks from text 14 | /// 15 | /// Removes paired asterisks (*) from text, but leaves adjacent asterisks 16 | /// untouched. For example: 17 | /// Original: Hello *world*, this is a **test** of *asterisks*. 18 | /// Modified: Hello world, this is a **test** of asterisks. 19 | fn remove_paired_asterisks(input_str: &str) -> String { 20 | let input: Vec = input_str.chars().collect(); 21 | const AST: char = '*'; 22 | const BRK: char = '\n'; 23 | let mut pos_to_elim: Vec = Vec::new(); 24 | let mut detecting_pair = false; 25 | let mut pair_start_index: usize = 0; 26 | for (i, ch) in input.iter().enumerate() { 27 | if *ch == AST { 28 | // if a part of a group of asterisks - skip. 29 | if let Some(c) = input.get(i + 1) { 30 | if *c == AST { 31 | continue; 32 | } 33 | } 34 | if let Some(c) = input.get(i.wrapping_sub(1)) { 35 | if *c == AST { 36 | continue; 37 | } 38 | } 39 | // Start detecting a pair 40 | if !detecting_pair { 41 | detecting_pair = true; 42 | pair_start_index = i; 43 | } 44 | // Pair detected - mark both for removal. 45 | else { 46 | pos_to_elim.push(pair_start_index); 47 | pos_to_elim.push(i); 48 | detecting_pair = false; 49 | } 50 | } 51 | if *ch == BRK { 52 | detecting_pair = false; 53 | } 54 | } 55 | 56 | // Now we have positions of all chars to eliminate. Copy to output all remaining chars. 57 | let res: String = input 58 | .iter() 59 | .enumerate() 60 | .filter(|(i, _)| !pos_to_elim.contains(i)) 61 | .map(|(_, v)| v) 62 | .collect(); 63 | res 64 | } 65 | 66 | /// Removes asterisks from relevant fields of tavern card 67 | pub fn deasterisk_tavern_card(tavern_card: &mut TavernCardV2) { 68 | let d = &mut tavern_card.data; 69 | let de8 = |x: &mut Option| { 70 | let t = x.as_ref().map(|y| remove_paired_asterisks(&y)); 71 | *x = t; 72 | }; 73 | de8(&mut d.description); 74 | de8(&mut d.personality); 75 | de8(&mut d.scenario); 76 | de8(&mut d.first_mes); 77 | de8(&mut d.mes_example); 78 | if let Some(cb) = &mut d.character_book { 79 | for e in &mut cb.entries { 80 | e.content = remove_paired_asterisks(&e.content); 81 | } 82 | } 83 | if let Some(ag) = &mut d.alternate_greetings { 84 | for g in ag.iter_mut() { 85 | *g = remove_paired_asterisks(g); 86 | } 87 | } 88 | } 89 | 90 | // Opens file, applies deasterisk to it, saves in new location. 91 | pub fn deasterisk_tavern_file( 92 | png_path: &Path, 93 | auto_overwrite: bool, 94 | ) -> Result<()> { 95 | println!("Deasterisk file: {}", &png_path.display()); 96 | let image_data = read_image_from_file(png_path)?; 97 | let mut card = TavernCardV2::from_png_image(&image_data)?; 98 | println!( 99 | "Character name is {}", 100 | card.data.name.to_owned().unwrap_or_else(|| "".to_string()) 101 | ); 102 | deasterisk_tavern_card(&mut card); 103 | 104 | info!("\nCHARACTER INFO:\n{:#?}", &card.data); 105 | 106 | // Build new file name. 107 | let file_name = png_path 108 | .file_name() 109 | .map_or("image.png".to_string(), |x| x.to_string_lossy().to_string()); 110 | let new_file_name = format!("de8.{}", file_name); 111 | println!("Output file name: {}", new_file_name); 112 | let new_path = png_path.with_file_name(new_file_name); 113 | 114 | // Check if output file already exists 115 | let path_exists = new_path.try_exists(); 116 | if let Err(e) = path_exists { 117 | bail!("Output path is not available: {}", e); 118 | } 119 | // If it exists - ask if it should be overwritten, unless `auto_overwrite` 120 | // is set to true (then always overwrite). 121 | if path_exists.unwrap() { 122 | let mut overwrite = auto_overwrite; 123 | if !auto_overwrite { 124 | println!("File {} already exists. Overwrite?", new_path.display()); 125 | let mut input = String::new(); 126 | std::io::stdin().read_line(&mut input)?; 127 | overwrite = input.trim().to_lowercase() == "y"; 128 | } 129 | if overwrite { 130 | std::fs::remove_file(&new_path)?; 131 | } else { 132 | bail!("File {} already exists ", new_path.display()); 133 | } 134 | }; 135 | 136 | // Save image to new name 137 | let new_image = card.into_png_image()?; 138 | tools::write_image_to_file(&new_image, &new_path)?; 139 | println!("Done"); 140 | Ok(()) 141 | } 142 | 143 | #[cfg(test)] 144 | mod tests { 145 | use super::*; 146 | 147 | #[test] 148 | fn test_remove_paired_asterisks() { 149 | assert_eq!( 150 | remove_paired_asterisks( 151 | "Hello *world*, this is a **test** of *asterisks*." 152 | ), 153 | "Hello world, this is a **test** of asterisks." 154 | ); 155 | assert_eq!( 156 | remove_paired_asterisks( 157 | "*This* is **bold** and *this* is *italic*." 158 | ), 159 | "This is **bold** and this is italic." 160 | ); 161 | assert_eq!( 162 | remove_paired_asterisks("No asterisks here."), 163 | "No asterisks here." 164 | ); 165 | assert_eq!( 166 | remove_paired_asterisks("Only *paired* asterisks."), 167 | "Only paired asterisks." 168 | ); 169 | assert_eq!( 170 | remove_paired_asterisks("Only **unpaired** asterisks."), 171 | "Only **unpaired** asterisks." 172 | ); 173 | assert_eq!( 174 | remove_paired_asterisks("Single* asterisk."), 175 | "Single* asterisk." 176 | ); 177 | assert_eq!( 178 | remove_paired_asterisks("***Triple*** asterisks."), 179 | "***Triple*** asterisks." 180 | ); 181 | assert_eq!( 182 | remove_paired_asterisks("*Example text of no importance*"), 183 | "Example text of no importance" 184 | ); 185 | assert_eq!( 186 | remove_paired_asterisks("**Example text of no importance**"), 187 | "**Example text of no importance**" 188 | ); 189 | } 190 | 191 | use crate::tavern_card_v2::*; 192 | 193 | #[test] 194 | fn test_deasterisk_tavern_card() { 195 | let mut card = TavernCardV2::new(); 196 | card.data.description = Some(String::from( 197 | "Hello *world*, this is a **test** of *asterisks*.", 198 | )); 199 | card.data.personality = 200 | Some(String::from("*This* is **bold** and *this* is *italic*.")); 201 | card.data.scenario = Some(String::from("No asterisks here.")); 202 | card.data.first_mes = Some(String::from("Only *paired* asterisks.")); 203 | card.data.mes_example = 204 | Some(String::from("Only **unpaired** asterisks.")); 205 | card.data.character_book = Some(CharacterBook::default()); 206 | //card.data.character_book.unwrap().entries 207 | let mut entry1 = CharacterBookEntry::default(); 208 | entry1.content = String::from("*Example text of no importance*"); 209 | 210 | let mut entry2 = CharacterBookEntry::default(); 211 | entry2.content = String::from("**Example text of no importance**"); 212 | 213 | card.data.character_book.as_mut().unwrap().entries.push(entry1); 214 | card.data.character_book.as_mut().unwrap().entries.push(entry2); 215 | 216 | deasterisk_tavern_card(&mut card); 217 | 218 | assert_eq!( 219 | card.data.description, 220 | Some(String::from("Hello world, this is a **test** of asterisks.")) 221 | ); 222 | assert_eq!( 223 | card.data.personality, 224 | Some(String::from("This is **bold** and this is italic.")) 225 | ); 226 | assert_eq!( 227 | card.data.scenario, 228 | Some(String::from("No asterisks here.")) 229 | ); 230 | assert_eq!( 231 | card.data.first_mes, 232 | Some(String::from("Only paired asterisks.")) 233 | ); 234 | assert_eq!( 235 | card.data.mes_example, 236 | Some(String::from("Only **unpaired** asterisks.")) 237 | ); 238 | assert_eq!( 239 | card.data.character_book.as_ref().unwrap().entries[0].content, 240 | String::from("Example text of no importance") 241 | ); 242 | assert_eq!( 243 | card.data.character_book.as_ref().unwrap().entries[1].content, 244 | String::from("**Example text of no importance**") 245 | ); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/tavern_card_v2.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use anyhow::{bail, Result}; 4 | use base64::prelude::*; 5 | use bytes::Bytes; 6 | use textwrap::{fill, Options}; 7 | 8 | use crate::tools; 9 | 10 | pub const TEXT_KEY_PNG: &str = "Chara"; 11 | 12 | #[derive(serde::Serialize, serde::Deserialize, Debug, Default, PartialEq)] 13 | pub struct CharacterBook { 14 | pub name: Option, 15 | pub description: Option, 16 | pub scan_depth: Option, 17 | pub token_budget: Option, 18 | pub recursive_scanning: Option, 19 | pub extensions: std::collections::HashMap, 20 | pub entries: Vec, 21 | } 22 | 23 | #[derive(serde::Serialize, serde::Deserialize, Debug, Default, PartialEq)] 24 | pub struct CharacterBookEntry { 25 | pub keys: Vec, 26 | pub content: String, 27 | pub extensions: std::collections::HashMap, 28 | pub enabled: bool, 29 | pub insertion_order: Option, 30 | pub case_sensitive: Option, 31 | pub name: Option, 32 | pub priority: Option, 33 | pub id: Option, 34 | pub comment: Option, 35 | pub selective: Option, 36 | pub secondary_keys: Option>, 37 | pub constant: Option, 38 | pub position: Option, 39 | } 40 | 41 | #[derive(serde::Serialize, serde::Deserialize, Debug, Default, PartialEq)] 42 | pub struct TavernCardV2 { 43 | pub spec: Option, 44 | pub spec_version: Option, 45 | pub data: CharacterData, 46 | #[serde(skip)] 47 | pub image_data: Option, // For keeping PNG image along 48 | } 49 | 50 | #[derive(serde::Serialize, serde::Deserialize, Debug, Default, PartialEq)] 51 | pub struct CharacterData { 52 | pub name: Option, 53 | pub description: Option, 54 | pub personality: Option, 55 | pub scenario: Option, 56 | pub first_mes: Option, 57 | pub mes_example: Option, 58 | pub creator_notes: Option, 59 | pub system_prompt: Option, 60 | pub post_history_instructions: Option, 61 | pub alternate_greetings: Option>, 62 | pub character_book: Option, 63 | pub tags: Option>, 64 | pub creator: Option, 65 | pub character_version: Option, 66 | pub extensions: 67 | Option>, 68 | } 69 | 70 | impl TavernCardV2 { 71 | pub fn new() -> Self { 72 | let mut s = TavernCardV2::default(); 73 | s.improve_card(); 74 | s 75 | } 76 | 77 | /// Writes card into image 78 | /// 79 | /// Makes a copy of PNG image, with card tag added to it. 80 | pub fn into_png_image(&self) -> Result { 81 | let json_string = serde_json::to_string(self)?; 82 | let base64_json_string = BASE64_STANDARD.encode(json_string); 83 | let temp_image_holder; 84 | let image_data; 85 | match &self.image_data { 86 | Some(img) => image_data = img, 87 | None => { 88 | temp_image_holder = tools::get_default_image(); 89 | image_data = &temp_image_holder; 90 | } 91 | } 92 | let edited_card = tools::write_text_to_png( 93 | TEXT_KEY_PNG, 94 | &base64_json_string, 95 | image_data, 96 | )?; 97 | Ok(edited_card) 98 | } 99 | 100 | pub fn from_png_image(image_data: &Bytes) -> Result { 101 | let raw_text = tools::read_text_chunk(image_data, TEXT_KEY_PNG)?; 102 | if raw_text.is_none() { 103 | bail!("No {} entry in PNG tEXt chunks", TEXT_KEY_PNG); 104 | }; 105 | let text = BASE64_STANDARD.decode(raw_text.unwrap())?; 106 | if !text.starts_with(&[b'{']) { 107 | bail!( 108 | "{} entry in PNG tEXt chunks does not start with '{{'", 109 | TEXT_KEY_PNG 110 | ); 111 | } 112 | // Try to convert tag into tavern card data 113 | let mut card = serde_json::from_slice::(&text); 114 | if card.is_err() { 115 | // Sometimes the tag contains only the data portion 116 | match serde_json::from_slice::(&text) { 117 | Ok(card_data) => { 118 | card = Ok(TavernCardV2 { 119 | data: card_data, 120 | ..Default::default() 121 | }); 122 | } 123 | Err(e) => { 124 | bail!( 125 | "Failed to parse {} entry in PNG tEXt chunks: {}", 126 | TEXT_KEY_PNG, 127 | e 128 | ); 129 | } 130 | } 131 | } 132 | let mut card = card.unwrap(); 133 | card.image_data = Some(image_data.clone()); 134 | Ok(card) 135 | } 136 | 137 | /// Make changes to better conform the specification 138 | fn improve_card(&mut self) { 139 | if self.spec.is_none() { 140 | self.spec = Some("chara_card_v2".to_string()); 141 | } 142 | if self.spec_version.is_none() { 143 | self.spec_version = Some("2.0".to_string()); 144 | } 145 | if self.data.name.is_none() { 146 | self.data.name = Some("".to_string()); 147 | } 148 | if self.data.description.is_none() { 149 | self.data.description = Some("NO NAME".to_string()); 150 | } 151 | } 152 | } 153 | 154 | impl Display for TavernCardV2 { 155 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 156 | // Turns &Option into &str 157 | fn no_opt(o: &Option) -> &str { 158 | const NONE_STR: &str = "NONE"; 159 | o.as_ref().map(|x| x.as_str()).unwrap_or(NONE_STR) 160 | } 161 | 162 | let mut lines = vec![ 163 | ("Character name:", no_opt(&self.data.name)), 164 | ("Description:", no_opt(&self.data.description)), 165 | ("Personality:", no_opt(&self.data.personality)), 166 | ("Scenario:", no_opt(&self.data.scenario)), 167 | ("First message:", no_opt(&self.data.first_mes)), 168 | ("Dialog example:", no_opt(&self.data.mes_example)), 169 | ("Creator notes:", no_opt(&self.data.creator_notes)), 170 | ("System prompt:", no_opt(&self.data.system_prompt)), 171 | ( 172 | "Post history instructions:", 173 | no_opt(&self.data.post_history_instructions), 174 | ), 175 | ("Creator:", no_opt(&self.data.creator)), 176 | ]; 177 | 178 | // Print alternative greetings, if present 179 | let ag_store; 180 | if let Some(alternative_greetings) = &self.data.alternate_greetings { 181 | ag_store = alternative_greetings.join("\n\n====\n\n"); 182 | lines.push(("Alternative greetings:", &ag_store)); 183 | } 184 | 185 | // Print lorebook 186 | let lb_store; 187 | if let Some(character_book) = &self.data.character_book { 188 | lb_store = character_book 189 | .entries 190 | .iter() 191 | .map(|x| (x.keys.join(","), &x.content)) 192 | .map(|x| { 193 | if x.0.is_empty() { 194 | ("NO KEYS".to_string(), x.1) 195 | } else { 196 | x 197 | } 198 | }) 199 | .map(|x| format!("{} : {}", x.0, x.1)) 200 | .collect::>() 201 | .join("\n"); 202 | lines.push(("Lorebook:", &lb_store)); 203 | } 204 | 205 | // Now to convert the lines vector into a pretty string 206 | let mut output = String::new(); 207 | let tw = *[textwrap::termwidth(), 80usize].iter().min().unwrap(); 208 | let options = 209 | Options::new(tw).initial_indent("").subsequent_indent(" "); 210 | for (key, value) in lines { 211 | let mut line = format!("{}: {}\n", key, value); 212 | line = fill(&line, &options); 213 | output += &line; 214 | } 215 | write!(f, "{}", output)?; 216 | 217 | Ok(()) 218 | } 219 | } 220 | 221 | #[cfg(test)] 222 | mod tests { 223 | 224 | use super::*; 225 | use anyhow::Result; 226 | 227 | #[allow(unused_imports)] 228 | use tools; 229 | 230 | fn create_test_card() -> TavernCardV2 { 231 | let mut card = TavernCardV2::new(); 232 | card.data.name = Some(String::from("Test name")); 233 | card.data.description = Some(String::from("Test description")); 234 | card.data.personality = Some(String::from("Test personality")); 235 | card.data.scenario = Some(String::from("Test scenario")); 236 | card.data.first_mes = Some(String::from("Test first message")); 237 | card.data.mes_example = Some(String::from("Test dialog example")); 238 | card.data.character_book = Some(CharacterBook::default()); 239 | let mut entry1 = CharacterBookEntry::default(); 240 | entry1.content = String::from("Test book entry 1"); 241 | 242 | let mut entry2 = CharacterBookEntry::default(); 243 | entry2.content = String::from("Test book entry 2"); 244 | 245 | card.data.character_book.as_mut().unwrap().entries.push(entry1); 246 | card.data.character_book.as_mut().unwrap().entries.push(entry2); 247 | card.image_data = Some(tools::get_default_image()); 248 | let image_with_tag = card.into_png_image().unwrap(); 249 | card.image_data = Some(image_with_tag); 250 | card 251 | } 252 | 253 | #[test] 254 | fn test_equal_sanity() { 255 | let card1 = create_test_card(); 256 | let card2 = create_test_card(); 257 | assert_eq!(card1, card2); 258 | } 259 | 260 | #[test] 261 | fn test_write_and_read() -> Result<()> { 262 | let card = create_test_card(); 263 | let image = card.into_png_image()?; 264 | let card2 = TavernCardV2::from_png_image(&image)?; 265 | assert_eq!(card, card2); 266 | // tools::write_image_to_file(&image, &std::path::Path::new("testing/test_card.png"))?; 267 | Ok(()) 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /src/baya_download.rs: -------------------------------------------------------------------------------- 1 | //! Tools to download a character from Backyard AI 2 | 3 | use std::{ 4 | io::{self, Write}, 5 | path::PathBuf, 6 | thread, 7 | time::Duration, 8 | }; 9 | 10 | use crate::{ 11 | tavern_card_v2::*, 12 | tools::{self, write_image_to_file}, 13 | }; 14 | 15 | use anyhow::{bail, Context, Result}; 16 | use chrono::{DateTime, Utc}; 17 | use log::info; 18 | use soup::prelude::*; 19 | 20 | #[allow(non_snake_case, dead_code)] 21 | #[derive(serde::Deserialize, Debug)] 22 | pub struct BayaCharacter { 23 | aiName: Option, 24 | aiDisplayName: Option, 25 | description: Option, 26 | authorNotes: Option, 27 | createdAt: DateTime, 28 | updatedAt: DateTime, 29 | aiPersona: Option, 30 | basePrompt: Option, 31 | customDialogue: Option, 32 | firstMessage: Option, 33 | scenario: Option, 34 | temperature: Option, 35 | repeatLastN: Option, 36 | repeatPenalty: Option, 37 | isNsfw: Option, 38 | grammar: Option, 39 | topP: Option, 40 | minP: Option, 41 | minPEnabled: Option, 42 | topK: Option, 43 | promptTemplate: Option, 44 | Author: Option, 45 | ModelFamily: Option, 46 | Tags: Vec, 47 | Images: Vec, 48 | Lorebook: Option, 49 | } 50 | 51 | #[allow(non_snake_case, dead_code)] 52 | #[derive(serde::Deserialize, Debug)] 53 | struct Lorebook { 54 | LorebookItems: Vec, 55 | } 56 | 57 | #[allow(non_snake_case, dead_code)] 58 | #[derive(serde::Deserialize, Debug)] 59 | struct LoreBookItem { 60 | key: String, 61 | order: String, 62 | value: String, 63 | } 64 | 65 | #[allow(non_snake_case, dead_code)] 66 | #[derive(serde::Deserialize, Debug)] 67 | struct Image { 68 | imageUrl: String, 69 | label: Option, 70 | } 71 | 72 | #[allow(non_snake_case, dead_code)] 73 | #[derive(serde::Deserialize, Debug)] 74 | struct Tag { 75 | name: String, 76 | } 77 | 78 | #[allow(non_snake_case, dead_code)] 79 | #[derive(serde::Deserialize, Debug)] 80 | struct Author { 81 | username: String, 82 | } 83 | 84 | #[allow(non_snake_case, dead_code)] 85 | #[derive(serde::Deserialize, Debug)] 86 | struct ModelFamily { 87 | displayName: String, 88 | promptFormat: String, 89 | } 90 | 91 | pub fn download_card_from_baya_url(url: &str) -> Result<()> { 92 | // Forcibly flush stdout before blocking operations, otherwise the line before long operations does not display. 93 | let flush = || io::stdout().flush().unwrap(); 94 | 95 | print!("Downloading web page: "); 96 | flush(); 97 | let body = tools::download_page(url)?; 98 | println!("Done!"); 99 | 100 | print!("Parsing downloaded page: "); 101 | let baya_character = 102 | parse_page(&body).context("Could not parse character JSON")?; 103 | println!("Done!"); 104 | 105 | let display_char_name: String = baya_character 106 | .aiDisplayName 107 | .clone() 108 | .unwrap_or_else(|| "NO_NAME_SET".to_string()); 109 | println!("Character name is: {}", display_char_name); 110 | 111 | info!("\nCHARACTER INFO:\n{:#?}", &baya_character); 112 | 113 | // Download the image, if it is linked on the page. Otherwise, use default image. 114 | let mut card_image = None; 115 | if !baya_character.Images.is_empty() { 116 | // Download the first image linked on card. 117 | let url = &baya_character.Images[0].imageUrl; 118 | print!("Downloading image: "); 119 | flush(); 120 | // Try to download image and check result 121 | let mut temp_img = tools::download_image(url); 122 | match temp_img { 123 | Err(e) => eprintln!("Could not download image because {}", e), 124 | Ok(img) => { 125 | // Try to convert img and check result 126 | temp_img = tools::convert_to_png(&img); 127 | match temp_img { 128 | Ok(img) => card_image = Some(img), 129 | Err(e) => eprintln!( 130 | "Could not convert image to PNG because {}", 131 | e 132 | ), 133 | }; 134 | } 135 | }; 136 | } else { 137 | print!("No image provided, using default image."); 138 | } 139 | println!("Done!"); 140 | 141 | print!("Writing tavern card: "); 142 | flush(); 143 | let mut tavern_card = TavernCardV2::from(&baya_character); 144 | tavern_card.image_data = card_image; 145 | 146 | info!("\nCONVERTED TAVERN CARD:\n{:#?}", &tavern_card); 147 | 148 | let tavern_image = 149 | tavern_card.into_png_image().context("Could not write tavern card")?; 150 | let card_name = PathBuf::from(format!("{}.png", display_char_name)); 151 | write_image_to_file(&tavern_image, &card_name)?; 152 | println!("Done!"); 153 | print!("Fap away!"); 154 | flush(); 155 | thread::sleep(Duration::from_millis(150)); 156 | println!("\rAll done!"); 157 | flush(); 158 | Ok(()) 159 | } 160 | 161 | /// Extracts character data from the downloaded web page. 162 | fn parse_page(body: &str) -> Result { 163 | let soup = soup::Soup::new(body); 164 | let scr = soup 165 | .tag("script") 166 | .attr("id", "__NEXT_DATA__") 167 | .find() 168 | .context("Did not find __NEXT_DATA__")?; 169 | 170 | let scr_text = scr.text(); 171 | 172 | info!("\nSCRIPT DATA:\n{:#?}", &scr_text); 173 | 174 | let mut json: serde_json::Value = serde_json::from_str(&scr.text()) 175 | .context("JSON was not well-formatted")?; 176 | 177 | let pointer = 178 | "/props/pageProps/trpcState/json/queries/0/state/data/character"; 179 | let char_json = 180 | json.pointer_mut(pointer).context("Could not find character block")?; 181 | 182 | let json_string = serde_json::to_string_pretty(&char_json)?; 183 | info!("\nCHAR JSON:\n{:#?}", &json_string); 184 | 185 | let ds = &mut serde_json::Deserializer::from_str(&json_string); 186 | let result: Result = serde_path_to_error::deserialize(ds); 187 | match result { 188 | Ok(bc) => Ok(bc), 189 | Err(e) => { 190 | let err_path = e.path().to_string(); 191 | bail!( 192 | "Could not parse character JSON: {:?} Error path: {:?}", 193 | e, 194 | err_path 195 | ); 196 | } 197 | } 198 | } 199 | 200 | /// Replace all instances of User 201 | /// 202 | /// The convention on Backyard characters is to adress user as "User" while SillyTavern convention 203 | /// is to use {{user}} instead. This function replaces all instances of User, trying to 204 | /// ignore compound words like Userland. 205 | fn convert_user_tag(text: &str) -> String { 206 | const CONVERT_FROM: &str = "User"; 207 | const CONVERT_INTO: &str = "{{user}}"; 208 | let mut result = String::new(); 209 | let mut last_match_end = 0; 210 | 211 | for (start, part) in text 212 | .match_indices(|c: char| c.is_whitespace() || c.is_ascii_punctuation()) 213 | { 214 | if start > last_match_end { 215 | let word = &text[last_match_end..start]; 216 | if word == CONVERT_FROM { 217 | result.push_str(CONVERT_INTO); 218 | } else { 219 | result.push_str(word); 220 | } 221 | } 222 | result.push_str(part); 223 | last_match_end = start + part.len(); 224 | } 225 | 226 | if last_match_end < text.len() { 227 | let last_word = &text[last_match_end..]; 228 | if last_word == CONVERT_FROM { 229 | result.push_str(CONVERT_INTO); 230 | } else { 231 | result.push_str(last_word); 232 | } 233 | } 234 | result 235 | } 236 | 237 | impl From<&BayaCharacter> for TavernCardV2 { 238 | fn from(character: &BayaCharacter) -> Self { 239 | let mut new_character = TavernCardV2::new(); 240 | let card_data = &mut new_character.data; 241 | 242 | let transfer_string = 243 | |s: &Option| s.clone().filter(|x| !x.is_empty()); 244 | 245 | let transfer_string_and_conv = 246 | |s| transfer_string(s).map(|x| convert_user_tag(&x)); 247 | 248 | card_data.name = transfer_string(&character.aiDisplayName); 249 | card_data.description = transfer_string_and_conv(&character.aiPersona); 250 | card_data.scenario = transfer_string_and_conv(&character.scenario); 251 | card_data.first_mes = transfer_string_and_conv(&character.firstMessage); 252 | card_data.mes_example = 253 | transfer_string_and_conv(&character.customDialogue); 254 | card_data.creator_notes = transfer_string(&character.authorNotes); 255 | card_data.system_prompt = 256 | transfer_string_and_conv(&character.basePrompt); 257 | card_data.personality = 258 | transfer_string_and_conv(&character.description); 259 | 260 | for tag in &character.Tags { 261 | if card_data.tags.is_none() { 262 | card_data.tags = Some(vec![]); 263 | } 264 | card_data.tags.as_mut().unwrap().push(tag.name.clone()); 265 | } 266 | 267 | let author_name = match &character.Author { 268 | Some(author) => author.username.clone(), 269 | None => "".to_string(), 270 | }; 271 | card_data.creator = transfer_string(&Some(author_name)); 272 | 273 | //Now copy the lorebook 274 | if let Some(lorebook) = &character.Lorebook { 275 | if !lorebook.LorebookItems.is_empty() { 276 | card_data.character_book = Some(lorebook.into()); 277 | } 278 | } 279 | 280 | new_character 281 | } 282 | } 283 | 284 | impl From<&LoreBookItem> for CharacterBookEntry { 285 | fn from(lorebook_entry: &LoreBookItem) -> Self { 286 | let mut new_entry = CharacterBookEntry::default(); 287 | new_entry.keys = lorebook_entry 288 | .key 289 | .split(",") 290 | .map(|x| x.trim().to_string()) 291 | .collect(); 292 | new_entry.content = lorebook_entry.value.clone(); 293 | new_entry 294 | } 295 | } 296 | 297 | impl From<&Lorebook> for CharacterBook { 298 | fn from(lorebook: &Lorebook) -> Self { 299 | let mut new_book = CharacterBook::default(); 300 | for lorebook_entry in &lorebook.LorebookItems { 301 | new_book.entries.push(lorebook_entry.into()); 302 | } 303 | new_book 304 | } 305 | } 306 | 307 | mod tests { 308 | use super::*; 309 | use anyhow::Result; 310 | use std::collections::HashMap; 311 | use test_context::{test_context, TestContext}; 312 | 313 | const CACHE_PATH: &str = "testing/test_cache.txt"; // Cache for downloaded pages will be stored here. 314 | 315 | #[derive(serde::Serialize, serde::Deserialize)] 316 | struct TestCache { 317 | page_cache: HashMap, 318 | } 319 | 320 | impl TestContext for TestCache { 321 | fn setup() -> Self { 322 | let file_content = std::fs::read_to_string(CACHE_PATH) 323 | .unwrap_or_else(|_| String::new()); 324 | serde_json::from_str(&file_content) 325 | .unwrap_or_else(|_| TestCache { page_cache: HashMap::new() }) 326 | } 327 | 328 | fn teardown(self) { 329 | let serialized = serde_json::to_string(&self) 330 | .expect("Failed to serialize cache"); 331 | std::fs::write(CACHE_PATH, serialized) 332 | .expect("Failed to write cache to file"); 333 | } 334 | } 335 | 336 | fn download_testing_webpage<'a>( 337 | url: &str, 338 | cache: &'a mut TestCache, 339 | ) -> Result<&'a str> { 340 | if cache.page_cache.contains_key(url) { 341 | return Ok(cache.page_cache.get(url).unwrap()); 342 | } 343 | let page_content = tools::download_page(url)?; 344 | cache.page_cache.insert(url.to_string(), page_content); 345 | return Ok(cache.page_cache.get(url).unwrap()); 346 | } 347 | 348 | #[test_context(TestCache)] 349 | #[test] 350 | fn test_downloading_page(cache: &mut TestCache) -> Result<()> { 351 | const TEST_URL: &str = 352 | "https://backyard.ai/hub/character/clmg7rj2e03j0mc0v69b1tai1"; 353 | let page = download_testing_webpage(TEST_URL, cache)?; 354 | let baya_char = parse_page(page)?; 355 | let baya_char_name = baya_char.aiDisplayName.unwrap(); 356 | assert_eq!(baya_char_name, "Character crafter Puppy"); 357 | Ok(()) 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.22.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "android-tzdata" 31 | version = "0.1.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 34 | 35 | [[package]] 36 | name = "android_system_properties" 37 | version = "0.1.5" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 40 | dependencies = [ 41 | "libc", 42 | ] 43 | 44 | [[package]] 45 | name = "anstream" 46 | version = "0.6.14" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 49 | dependencies = [ 50 | "anstyle", 51 | "anstyle-parse", 52 | "anstyle-query", 53 | "anstyle-wincon", 54 | "colorchoice", 55 | "is_terminal_polyfill", 56 | "utf8parse", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle" 61 | version = "1.0.7" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 64 | 65 | [[package]] 66 | name = "anstyle-parse" 67 | version = "0.2.4" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 70 | dependencies = [ 71 | "utf8parse", 72 | ] 73 | 74 | [[package]] 75 | name = "anstyle-query" 76 | version = "1.1.0" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" 79 | dependencies = [ 80 | "windows-sys 0.52.0", 81 | ] 82 | 83 | [[package]] 84 | name = "anstyle-wincon" 85 | version = "3.0.3" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 88 | dependencies = [ 89 | "anstyle", 90 | "windows-sys 0.52.0", 91 | ] 92 | 93 | [[package]] 94 | name = "anyhow" 95 | version = "1.0.86" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" 98 | 99 | [[package]] 100 | name = "atomic-waker" 101 | version = "1.1.2" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 104 | 105 | [[package]] 106 | name = "autocfg" 107 | version = "0.1.8" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" 110 | dependencies = [ 111 | "autocfg 1.3.0", 112 | ] 113 | 114 | [[package]] 115 | name = "autocfg" 116 | version = "1.3.0" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 119 | 120 | [[package]] 121 | name = "backtrace" 122 | version = "0.3.73" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" 125 | dependencies = [ 126 | "addr2line", 127 | "cc", 128 | "cfg-if", 129 | "libc", 130 | "miniz_oxide", 131 | "object", 132 | "rustc-demangle", 133 | ] 134 | 135 | [[package]] 136 | name = "base64" 137 | version = "0.22.1" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 140 | 141 | [[package]] 142 | name = "bitflags" 143 | version = "1.3.2" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 146 | 147 | [[package]] 148 | name = "bitflags" 149 | version = "2.6.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 152 | 153 | [[package]] 154 | name = "bumpalo" 155 | version = "3.16.0" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 158 | 159 | [[package]] 160 | name = "bytemuck" 161 | version = "1.16.1" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" 164 | 165 | [[package]] 166 | name = "byteorder" 167 | version = "1.5.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 170 | 171 | [[package]] 172 | name = "byteorder-lite" 173 | version = "0.1.0" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" 176 | 177 | [[package]] 178 | name = "bytes" 179 | version = "1.6.1" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" 182 | dependencies = [ 183 | "serde", 184 | ] 185 | 186 | [[package]] 187 | name = "cc" 188 | version = "1.1.5" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" 191 | 192 | [[package]] 193 | name = "cfg-if" 194 | version = "1.0.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 197 | 198 | [[package]] 199 | name = "chrono" 200 | version = "0.4.38" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 203 | dependencies = [ 204 | "android-tzdata", 205 | "iana-time-zone", 206 | "js-sys", 207 | "num-traits", 208 | "serde", 209 | "wasm-bindgen", 210 | "windows-targets 0.52.6", 211 | ] 212 | 213 | [[package]] 214 | name = "clap" 215 | version = "4.5.9" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" 218 | dependencies = [ 219 | "clap_builder", 220 | "clap_derive", 221 | ] 222 | 223 | [[package]] 224 | name = "clap_builder" 225 | version = "4.5.9" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" 228 | dependencies = [ 229 | "anstream", 230 | "anstyle", 231 | "clap_lex", 232 | "strsim", 233 | "unicase", 234 | "unicode-width", 235 | ] 236 | 237 | [[package]] 238 | name = "clap_derive" 239 | version = "4.5.8" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" 242 | dependencies = [ 243 | "heck", 244 | "proc-macro2 1.0.86", 245 | "quote 1.0.36", 246 | "syn 2.0.71", 247 | ] 248 | 249 | [[package]] 250 | name = "clap_lex" 251 | version = "0.7.1" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" 254 | 255 | [[package]] 256 | name = "cloudabi" 257 | version = "0.0.3" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 260 | dependencies = [ 261 | "bitflags 1.3.2", 262 | ] 263 | 264 | [[package]] 265 | name = "color_quant" 266 | version = "1.1.0" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" 269 | 270 | [[package]] 271 | name = "colorchoice" 272 | version = "1.0.1" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 275 | 276 | [[package]] 277 | name = "core-foundation" 278 | version = "0.9.4" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 281 | dependencies = [ 282 | "core-foundation-sys", 283 | "libc", 284 | ] 285 | 286 | [[package]] 287 | name = "core-foundation-sys" 288 | version = "0.8.6" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 291 | 292 | [[package]] 293 | name = "crc32fast" 294 | version = "1.4.2" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 297 | dependencies = [ 298 | "cfg-if", 299 | ] 300 | 301 | [[package]] 302 | name = "encoding_rs" 303 | version = "0.8.34" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 306 | dependencies = [ 307 | "cfg-if", 308 | ] 309 | 310 | [[package]] 311 | name = "env_filter" 312 | version = "0.1.0" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" 315 | dependencies = [ 316 | "log", 317 | "regex", 318 | ] 319 | 320 | [[package]] 321 | name = "env_logger" 322 | version = "0.11.3" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" 325 | dependencies = [ 326 | "anstream", 327 | "anstyle", 328 | "env_filter", 329 | "humantime", 330 | "log", 331 | ] 332 | 333 | [[package]] 334 | name = "equivalent" 335 | version = "1.0.1" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 338 | 339 | [[package]] 340 | name = "errno" 341 | version = "0.3.9" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 344 | dependencies = [ 345 | "libc", 346 | "windows-sys 0.52.0", 347 | ] 348 | 349 | [[package]] 350 | name = "fastrand" 351 | version = "2.1.0" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" 354 | 355 | [[package]] 356 | name = "fdeflate" 357 | version = "0.3.4" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" 360 | dependencies = [ 361 | "simd-adler32", 362 | ] 363 | 364 | [[package]] 365 | name = "flate2" 366 | version = "1.0.30" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" 369 | dependencies = [ 370 | "crc32fast", 371 | "miniz_oxide", 372 | ] 373 | 374 | [[package]] 375 | name = "fnv" 376 | version = "1.0.7" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 379 | 380 | [[package]] 381 | name = "foreign-types" 382 | version = "0.3.2" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 385 | dependencies = [ 386 | "foreign-types-shared", 387 | ] 388 | 389 | [[package]] 390 | name = "foreign-types-shared" 391 | version = "0.1.1" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 394 | 395 | [[package]] 396 | name = "form_urlencoded" 397 | version = "1.2.1" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 400 | dependencies = [ 401 | "percent-encoding", 402 | ] 403 | 404 | [[package]] 405 | name = "fuchsia-cprng" 406 | version = "0.1.1" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 409 | 410 | [[package]] 411 | name = "futf" 412 | version = "0.1.5" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" 415 | dependencies = [ 416 | "mac", 417 | "new_debug_unreachable", 418 | ] 419 | 420 | [[package]] 421 | name = "futures" 422 | version = "0.3.30" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" 425 | dependencies = [ 426 | "futures-channel", 427 | "futures-core", 428 | "futures-executor", 429 | "futures-io", 430 | "futures-sink", 431 | "futures-task", 432 | "futures-util", 433 | ] 434 | 435 | [[package]] 436 | name = "futures-channel" 437 | version = "0.3.30" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 440 | dependencies = [ 441 | "futures-core", 442 | "futures-sink", 443 | ] 444 | 445 | [[package]] 446 | name = "futures-core" 447 | version = "0.3.30" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 450 | 451 | [[package]] 452 | name = "futures-executor" 453 | version = "0.3.30" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" 456 | dependencies = [ 457 | "futures-core", 458 | "futures-task", 459 | "futures-util", 460 | ] 461 | 462 | [[package]] 463 | name = "futures-io" 464 | version = "0.3.30" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 467 | 468 | [[package]] 469 | name = "futures-macro" 470 | version = "0.3.30" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" 473 | dependencies = [ 474 | "proc-macro2 1.0.86", 475 | "quote 1.0.36", 476 | "syn 2.0.71", 477 | ] 478 | 479 | [[package]] 480 | name = "futures-sink" 481 | version = "0.3.30" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 484 | 485 | [[package]] 486 | name = "futures-task" 487 | version = "0.3.30" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 490 | 491 | [[package]] 492 | name = "futures-util" 493 | version = "0.3.30" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 496 | dependencies = [ 497 | "futures-channel", 498 | "futures-core", 499 | "futures-io", 500 | "futures-macro", 501 | "futures-sink", 502 | "futures-task", 503 | "memchr", 504 | "pin-project-lite", 505 | "pin-utils", 506 | "slab", 507 | ] 508 | 509 | [[package]] 510 | name = "getrandom" 511 | version = "0.2.15" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 514 | dependencies = [ 515 | "cfg-if", 516 | "libc", 517 | "wasi", 518 | ] 519 | 520 | [[package]] 521 | name = "gif" 522 | version = "0.13.1" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" 525 | dependencies = [ 526 | "color_quant", 527 | "weezl", 528 | ] 529 | 530 | [[package]] 531 | name = "gimli" 532 | version = "0.29.0" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 535 | 536 | [[package]] 537 | name = "h2" 538 | version = "0.4.5" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" 541 | dependencies = [ 542 | "atomic-waker", 543 | "bytes", 544 | "fnv", 545 | "futures-core", 546 | "futures-sink", 547 | "http", 548 | "indexmap", 549 | "slab", 550 | "tokio", 551 | "tokio-util", 552 | "tracing", 553 | ] 554 | 555 | [[package]] 556 | name = "hashbrown" 557 | version = "0.14.5" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 560 | 561 | [[package]] 562 | name = "heck" 563 | version = "0.5.0" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 566 | 567 | [[package]] 568 | name = "hermit-abi" 569 | version = "0.3.9" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 572 | 573 | [[package]] 574 | name = "html5ever" 575 | version = "0.22.5" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "c213fa6a618dc1da552f54f85cba74b05d8e883c92ec4e89067736938084c26e" 578 | dependencies = [ 579 | "log", 580 | "mac", 581 | "markup5ever", 582 | "proc-macro2 0.4.30", 583 | "quote 0.6.13", 584 | "syn 0.15.44", 585 | ] 586 | 587 | [[package]] 588 | name = "http" 589 | version = "1.1.0" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 592 | dependencies = [ 593 | "bytes", 594 | "fnv", 595 | "itoa", 596 | ] 597 | 598 | [[package]] 599 | name = "http-body" 600 | version = "1.0.1" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 603 | dependencies = [ 604 | "bytes", 605 | "http", 606 | ] 607 | 608 | [[package]] 609 | name = "http-body-util" 610 | version = "0.1.2" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 613 | dependencies = [ 614 | "bytes", 615 | "futures-util", 616 | "http", 617 | "http-body", 618 | "pin-project-lite", 619 | ] 620 | 621 | [[package]] 622 | name = "httparse" 623 | version = "1.9.4" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" 626 | 627 | [[package]] 628 | name = "humantime" 629 | version = "2.1.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 632 | 633 | [[package]] 634 | name = "hyper" 635 | version = "1.4.1" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" 638 | dependencies = [ 639 | "bytes", 640 | "futures-channel", 641 | "futures-util", 642 | "h2", 643 | "http", 644 | "http-body", 645 | "httparse", 646 | "itoa", 647 | "pin-project-lite", 648 | "smallvec", 649 | "tokio", 650 | "want", 651 | ] 652 | 653 | [[package]] 654 | name = "hyper-rustls" 655 | version = "0.27.2" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" 658 | dependencies = [ 659 | "futures-util", 660 | "http", 661 | "hyper", 662 | "hyper-util", 663 | "rustls", 664 | "rustls-pki-types", 665 | "tokio", 666 | "tokio-rustls", 667 | "tower-service", 668 | ] 669 | 670 | [[package]] 671 | name = "hyper-tls" 672 | version = "0.6.0" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 675 | dependencies = [ 676 | "bytes", 677 | "http-body-util", 678 | "hyper", 679 | "hyper-util", 680 | "native-tls", 681 | "tokio", 682 | "tokio-native-tls", 683 | "tower-service", 684 | ] 685 | 686 | [[package]] 687 | name = "hyper-util" 688 | version = "0.1.6" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" 691 | dependencies = [ 692 | "bytes", 693 | "futures-channel", 694 | "futures-util", 695 | "http", 696 | "http-body", 697 | "hyper", 698 | "pin-project-lite", 699 | "socket2", 700 | "tokio", 701 | "tower", 702 | "tower-service", 703 | "tracing", 704 | ] 705 | 706 | [[package]] 707 | name = "iana-time-zone" 708 | version = "0.1.60" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" 711 | dependencies = [ 712 | "android_system_properties", 713 | "core-foundation-sys", 714 | "iana-time-zone-haiku", 715 | "js-sys", 716 | "wasm-bindgen", 717 | "windows-core", 718 | ] 719 | 720 | [[package]] 721 | name = "iana-time-zone-haiku" 722 | version = "0.1.2" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 725 | dependencies = [ 726 | "cc", 727 | ] 728 | 729 | [[package]] 730 | name = "idna" 731 | version = "0.5.0" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 734 | dependencies = [ 735 | "unicode-bidi", 736 | "unicode-normalization", 737 | ] 738 | 739 | [[package]] 740 | name = "image" 741 | version = "0.25.1" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" 744 | dependencies = [ 745 | "bytemuck", 746 | "byteorder", 747 | "color_quant", 748 | "gif", 749 | "image-webp", 750 | "num-traits", 751 | "png", 752 | "zune-core", 753 | "zune-jpeg", 754 | ] 755 | 756 | [[package]] 757 | name = "image-webp" 758 | version = "0.1.3" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904" 761 | dependencies = [ 762 | "byteorder-lite", 763 | "quick-error", 764 | ] 765 | 766 | [[package]] 767 | name = "indexmap" 768 | version = "2.2.6" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 771 | dependencies = [ 772 | "equivalent", 773 | "hashbrown", 774 | ] 775 | 776 | [[package]] 777 | name = "io-lifetimes" 778 | version = "1.0.11" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" 781 | dependencies = [ 782 | "hermit-abi", 783 | "libc", 784 | "windows-sys 0.48.0", 785 | ] 786 | 787 | [[package]] 788 | name = "ipnet" 789 | version = "2.9.0" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" 792 | 793 | [[package]] 794 | name = "is_terminal_polyfill" 795 | version = "1.70.0" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 798 | 799 | [[package]] 800 | name = "itoa" 801 | version = "1.0.11" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 804 | 805 | [[package]] 806 | name = "js-sys" 807 | version = "0.3.69" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 810 | dependencies = [ 811 | "wasm-bindgen", 812 | ] 813 | 814 | [[package]] 815 | name = "lazy_static" 816 | version = "1.5.0" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 819 | 820 | [[package]] 821 | name = "libc" 822 | version = "0.2.155" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 825 | 826 | [[package]] 827 | name = "linux-raw-sys" 828 | version = "0.3.8" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" 831 | 832 | [[package]] 833 | name = "linux-raw-sys" 834 | version = "0.4.14" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 837 | 838 | [[package]] 839 | name = "log" 840 | version = "0.4.22" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 843 | dependencies = [ 844 | "serde", 845 | ] 846 | 847 | [[package]] 848 | name = "mac" 849 | version = "0.1.1" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 852 | 853 | [[package]] 854 | name = "markup5ever" 855 | version = "0.7.5" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "897636f9850c3eef4905a5540683ed53dc9393860f0846cab2c2ddf9939862ff" 858 | dependencies = [ 859 | "phf", 860 | "phf_codegen", 861 | "serde", 862 | "serde_derive", 863 | "serde_json", 864 | "string_cache", 865 | "string_cache_codegen", 866 | "tendril", 867 | ] 868 | 869 | [[package]] 870 | name = "memchr" 871 | version = "2.7.4" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 874 | 875 | [[package]] 876 | name = "mime" 877 | version = "0.3.17" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 880 | 881 | [[package]] 882 | name = "miniz_oxide" 883 | version = "0.7.4" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 886 | dependencies = [ 887 | "adler", 888 | "simd-adler32", 889 | ] 890 | 891 | [[package]] 892 | name = "mio" 893 | version = "0.8.11" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 896 | dependencies = [ 897 | "libc", 898 | "wasi", 899 | "windows-sys 0.48.0", 900 | ] 901 | 902 | [[package]] 903 | name = "native-tls" 904 | version = "0.2.12" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 907 | dependencies = [ 908 | "libc", 909 | "log", 910 | "openssl", 911 | "openssl-probe", 912 | "openssl-sys", 913 | "schannel", 914 | "security-framework", 915 | "security-framework-sys", 916 | "tempfile", 917 | ] 918 | 919 | [[package]] 920 | name = "new_debug_unreachable" 921 | version = "1.0.6" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" 924 | 925 | [[package]] 926 | name = "num-traits" 927 | version = "0.2.19" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 930 | dependencies = [ 931 | "autocfg 1.3.0", 932 | ] 933 | 934 | [[package]] 935 | name = "object" 936 | version = "0.36.1" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" 939 | dependencies = [ 940 | "memchr", 941 | ] 942 | 943 | [[package]] 944 | name = "once_cell" 945 | version = "1.19.0" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 948 | 949 | [[package]] 950 | name = "openssl" 951 | version = "0.10.64" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" 954 | dependencies = [ 955 | "bitflags 2.6.0", 956 | "cfg-if", 957 | "foreign-types", 958 | "libc", 959 | "once_cell", 960 | "openssl-macros", 961 | "openssl-sys", 962 | ] 963 | 964 | [[package]] 965 | name = "openssl-macros" 966 | version = "0.1.1" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 969 | dependencies = [ 970 | "proc-macro2 1.0.86", 971 | "quote 1.0.36", 972 | "syn 2.0.71", 973 | ] 974 | 975 | [[package]] 976 | name = "openssl-probe" 977 | version = "0.1.5" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 980 | 981 | [[package]] 982 | name = "openssl-sys" 983 | version = "0.9.102" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" 986 | dependencies = [ 987 | "cc", 988 | "libc", 989 | "pkg-config", 990 | "vcpkg", 991 | ] 992 | 993 | [[package]] 994 | name = "percent-encoding" 995 | version = "2.3.1" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 998 | 999 | [[package]] 1000 | name = "phf" 1001 | version = "0.7.24" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" 1004 | dependencies = [ 1005 | "phf_shared", 1006 | ] 1007 | 1008 | [[package]] 1009 | name = "phf_codegen" 1010 | version = "0.7.24" 1011 | source = "registry+https://github.com/rust-lang/crates.io-index" 1012 | checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" 1013 | dependencies = [ 1014 | "phf_generator", 1015 | "phf_shared", 1016 | ] 1017 | 1018 | [[package]] 1019 | name = "phf_generator" 1020 | version = "0.7.24" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" 1023 | dependencies = [ 1024 | "phf_shared", 1025 | "rand", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "phf_shared" 1030 | version = "0.7.24" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" 1033 | dependencies = [ 1034 | "siphasher", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "pin-project" 1039 | version = "1.1.5" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" 1042 | dependencies = [ 1043 | "pin-project-internal", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "pin-project-internal" 1048 | version = "1.1.5" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" 1051 | dependencies = [ 1052 | "proc-macro2 1.0.86", 1053 | "quote 1.0.36", 1054 | "syn 2.0.71", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "pin-project-lite" 1059 | version = "0.2.14" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 1062 | 1063 | [[package]] 1064 | name = "pin-utils" 1065 | version = "0.1.0" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1068 | 1069 | [[package]] 1070 | name = "pkg-config" 1071 | version = "0.3.30" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 1074 | 1075 | [[package]] 1076 | name = "png" 1077 | version = "0.17.13" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" 1080 | dependencies = [ 1081 | "bitflags 1.3.2", 1082 | "crc32fast", 1083 | "fdeflate", 1084 | "flate2", 1085 | "miniz_oxide", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "precomputed-hash" 1090 | version = "0.1.1" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 1093 | 1094 | [[package]] 1095 | name = "proc-macro2" 1096 | version = "0.4.30" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 1099 | dependencies = [ 1100 | "unicode-xid", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "proc-macro2" 1105 | version = "1.0.86" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 1108 | dependencies = [ 1109 | "unicode-ident", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "quick-error" 1114 | version = "2.0.1" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" 1117 | 1118 | [[package]] 1119 | name = "quote" 1120 | version = "0.6.13" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 1123 | dependencies = [ 1124 | "proc-macro2 0.4.30", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "quote" 1129 | version = "1.0.36" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 1132 | dependencies = [ 1133 | "proc-macro2 1.0.86", 1134 | ] 1135 | 1136 | [[package]] 1137 | name = "rand" 1138 | version = "0.6.5" 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" 1140 | checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1141 | dependencies = [ 1142 | "autocfg 0.1.8", 1143 | "libc", 1144 | "rand_chacha", 1145 | "rand_core 0.4.2", 1146 | "rand_hc", 1147 | "rand_isaac", 1148 | "rand_jitter", 1149 | "rand_os", 1150 | "rand_pcg", 1151 | "rand_xorshift", 1152 | "winapi", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "rand_chacha" 1157 | version = "0.1.1" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 1160 | dependencies = [ 1161 | "autocfg 0.1.8", 1162 | "rand_core 0.3.1", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "rand_core" 1167 | version = "0.3.1" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 1170 | dependencies = [ 1171 | "rand_core 0.4.2", 1172 | ] 1173 | 1174 | [[package]] 1175 | name = "rand_core" 1176 | version = "0.4.2" 1177 | source = "registry+https://github.com/rust-lang/crates.io-index" 1178 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 1179 | 1180 | [[package]] 1181 | name = "rand_hc" 1182 | version = "0.1.0" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" 1185 | dependencies = [ 1186 | "rand_core 0.3.1", 1187 | ] 1188 | 1189 | [[package]] 1190 | name = "rand_isaac" 1191 | version = "0.1.1" 1192 | source = "registry+https://github.com/rust-lang/crates.io-index" 1193 | checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" 1194 | dependencies = [ 1195 | "rand_core 0.3.1", 1196 | ] 1197 | 1198 | [[package]] 1199 | name = "rand_jitter" 1200 | version = "0.1.4" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" 1203 | dependencies = [ 1204 | "libc", 1205 | "rand_core 0.4.2", 1206 | "winapi", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "rand_os" 1211 | version = "0.1.3" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 1214 | dependencies = [ 1215 | "cloudabi", 1216 | "fuchsia-cprng", 1217 | "libc", 1218 | "rand_core 0.4.2", 1219 | "rdrand", 1220 | "winapi", 1221 | ] 1222 | 1223 | [[package]] 1224 | name = "rand_pcg" 1225 | version = "0.1.2" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 1228 | dependencies = [ 1229 | "autocfg 0.1.8", 1230 | "rand_core 0.4.2", 1231 | ] 1232 | 1233 | [[package]] 1234 | name = "rand_xorshift" 1235 | version = "0.1.1" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 1238 | dependencies = [ 1239 | "rand_core 0.3.1", 1240 | ] 1241 | 1242 | [[package]] 1243 | name = "rdrand" 1244 | version = "0.4.0" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 1247 | dependencies = [ 1248 | "rand_core 0.3.1", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "regex" 1253 | version = "1.10.5" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" 1256 | dependencies = [ 1257 | "aho-corasick", 1258 | "memchr", 1259 | "regex-automata", 1260 | "regex-syntax", 1261 | ] 1262 | 1263 | [[package]] 1264 | name = "regex-automata" 1265 | version = "0.4.7" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 1268 | dependencies = [ 1269 | "aho-corasick", 1270 | "memchr", 1271 | "regex-syntax", 1272 | ] 1273 | 1274 | [[package]] 1275 | name = "regex-syntax" 1276 | version = "0.8.4" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 1279 | 1280 | [[package]] 1281 | name = "reqwest" 1282 | version = "0.12.5" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" 1285 | dependencies = [ 1286 | "base64", 1287 | "bytes", 1288 | "encoding_rs", 1289 | "futures-channel", 1290 | "futures-core", 1291 | "futures-util", 1292 | "h2", 1293 | "http", 1294 | "http-body", 1295 | "http-body-util", 1296 | "hyper", 1297 | "hyper-rustls", 1298 | "hyper-tls", 1299 | "hyper-util", 1300 | "ipnet", 1301 | "js-sys", 1302 | "log", 1303 | "mime", 1304 | "native-tls", 1305 | "once_cell", 1306 | "percent-encoding", 1307 | "pin-project-lite", 1308 | "rustls-pemfile", 1309 | "serde", 1310 | "serde_json", 1311 | "serde_urlencoded", 1312 | "sync_wrapper", 1313 | "system-configuration", 1314 | "tokio", 1315 | "tokio-native-tls", 1316 | "tower-service", 1317 | "url", 1318 | "wasm-bindgen", 1319 | "wasm-bindgen-futures", 1320 | "web-sys", 1321 | "winreg", 1322 | ] 1323 | 1324 | [[package]] 1325 | name = "ring" 1326 | version = "0.17.8" 1327 | source = "registry+https://github.com/rust-lang/crates.io-index" 1328 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1329 | dependencies = [ 1330 | "cc", 1331 | "cfg-if", 1332 | "getrandom", 1333 | "libc", 1334 | "spin", 1335 | "untrusted", 1336 | "windows-sys 0.52.0", 1337 | ] 1338 | 1339 | [[package]] 1340 | name = "rustc-demangle" 1341 | version = "0.1.24" 1342 | source = "registry+https://github.com/rust-lang/crates.io-index" 1343 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1344 | 1345 | [[package]] 1346 | name = "rustix" 1347 | version = "0.37.27" 1348 | source = "registry+https://github.com/rust-lang/crates.io-index" 1349 | checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" 1350 | dependencies = [ 1351 | "bitflags 1.3.2", 1352 | "errno", 1353 | "io-lifetimes", 1354 | "libc", 1355 | "linux-raw-sys 0.3.8", 1356 | "windows-sys 0.48.0", 1357 | ] 1358 | 1359 | [[package]] 1360 | name = "rustix" 1361 | version = "0.38.34" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 1364 | dependencies = [ 1365 | "bitflags 2.6.0", 1366 | "errno", 1367 | "libc", 1368 | "linux-raw-sys 0.4.14", 1369 | "windows-sys 0.52.0", 1370 | ] 1371 | 1372 | [[package]] 1373 | name = "rustls" 1374 | version = "0.23.11" 1375 | source = "registry+https://github.com/rust-lang/crates.io-index" 1376 | checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" 1377 | dependencies = [ 1378 | "once_cell", 1379 | "rustls-pki-types", 1380 | "rustls-webpki", 1381 | "subtle", 1382 | "zeroize", 1383 | ] 1384 | 1385 | [[package]] 1386 | name = "rustls-pemfile" 1387 | version = "2.1.2" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" 1390 | dependencies = [ 1391 | "base64", 1392 | "rustls-pki-types", 1393 | ] 1394 | 1395 | [[package]] 1396 | name = "rustls-pki-types" 1397 | version = "1.7.0" 1398 | source = "registry+https://github.com/rust-lang/crates.io-index" 1399 | checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" 1400 | 1401 | [[package]] 1402 | name = "rustls-webpki" 1403 | version = "0.102.5" 1404 | source = "registry+https://github.com/rust-lang/crates.io-index" 1405 | checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" 1406 | dependencies = [ 1407 | "ring", 1408 | "rustls-pki-types", 1409 | "untrusted", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "ryu" 1414 | version = "1.0.18" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1417 | 1418 | [[package]] 1419 | name = "schannel" 1420 | version = "0.1.23" 1421 | source = "registry+https://github.com/rust-lang/crates.io-index" 1422 | checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" 1423 | dependencies = [ 1424 | "windows-sys 0.52.0", 1425 | ] 1426 | 1427 | [[package]] 1428 | name = "security-framework" 1429 | version = "2.11.1" 1430 | source = "registry+https://github.com/rust-lang/crates.io-index" 1431 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1432 | dependencies = [ 1433 | "bitflags 2.6.0", 1434 | "core-foundation", 1435 | "core-foundation-sys", 1436 | "libc", 1437 | "security-framework-sys", 1438 | ] 1439 | 1440 | [[package]] 1441 | name = "security-framework-sys" 1442 | version = "2.11.1" 1443 | source = "registry+https://github.com/rust-lang/crates.io-index" 1444 | checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" 1445 | dependencies = [ 1446 | "core-foundation-sys", 1447 | "libc", 1448 | ] 1449 | 1450 | [[package]] 1451 | name = "serde" 1452 | version = "1.0.204" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" 1455 | dependencies = [ 1456 | "serde_derive", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "serde-transcode" 1461 | version = "1.1.1" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "590c0e25c2a5bb6e85bf5c1bce768ceb86b316e7a01bdf07d2cb4ec2271990e2" 1464 | dependencies = [ 1465 | "serde", 1466 | ] 1467 | 1468 | [[package]] 1469 | name = "serde_derive" 1470 | version = "1.0.204" 1471 | source = "registry+https://github.com/rust-lang/crates.io-index" 1472 | checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" 1473 | dependencies = [ 1474 | "proc-macro2 1.0.86", 1475 | "quote 1.0.36", 1476 | "syn 2.0.71", 1477 | ] 1478 | 1479 | [[package]] 1480 | name = "serde_json" 1481 | version = "1.0.120" 1482 | source = "registry+https://github.com/rust-lang/crates.io-index" 1483 | checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" 1484 | dependencies = [ 1485 | "itoa", 1486 | "ryu", 1487 | "serde", 1488 | ] 1489 | 1490 | [[package]] 1491 | name = "serde_path_to_error" 1492 | version = "0.1.16" 1493 | source = "registry+https://github.com/rust-lang/crates.io-index" 1494 | checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" 1495 | dependencies = [ 1496 | "itoa", 1497 | "serde", 1498 | ] 1499 | 1500 | [[package]] 1501 | name = "serde_urlencoded" 1502 | version = "0.7.1" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1505 | dependencies = [ 1506 | "form_urlencoded", 1507 | "itoa", 1508 | "ryu", 1509 | "serde", 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "simd-adler32" 1514 | version = "0.3.7" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 1517 | 1518 | [[package]] 1519 | name = "siphasher" 1520 | version = "0.2.3" 1521 | source = "registry+https://github.com/rust-lang/crates.io-index" 1522 | checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" 1523 | 1524 | [[package]] 1525 | name = "slab" 1526 | version = "0.4.9" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1529 | dependencies = [ 1530 | "autocfg 1.3.0", 1531 | ] 1532 | 1533 | [[package]] 1534 | name = "smallvec" 1535 | version = "1.13.2" 1536 | source = "registry+https://github.com/rust-lang/crates.io-index" 1537 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1538 | 1539 | [[package]] 1540 | name = "smawk" 1541 | version = "0.3.2" 1542 | source = "registry+https://github.com/rust-lang/crates.io-index" 1543 | checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" 1544 | 1545 | [[package]] 1546 | name = "socket2" 1547 | version = "0.5.7" 1548 | source = "registry+https://github.com/rust-lang/crates.io-index" 1549 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 1550 | dependencies = [ 1551 | "libc", 1552 | "windows-sys 0.52.0", 1553 | ] 1554 | 1555 | [[package]] 1556 | name = "soup" 1557 | version = "0.5.1" 1558 | source = "registry+https://github.com/rust-lang/crates.io-index" 1559 | checksum = "aa5a5d21523f4b7a17ad04eaf534360fc908879f53f3341918cbec2fee9cfe14" 1560 | dependencies = [ 1561 | "html5ever", 1562 | "regex", 1563 | ] 1564 | 1565 | [[package]] 1566 | name = "spin" 1567 | version = "0.9.8" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1570 | 1571 | [[package]] 1572 | name = "string_cache" 1573 | version = "0.7.5" 1574 | source = "registry+https://github.com/rust-lang/crates.io-index" 1575 | checksum = "89c058a82f9fd69b1becf8c274f412281038877c553182f1d02eb027045a2d67" 1576 | dependencies = [ 1577 | "lazy_static", 1578 | "new_debug_unreachable", 1579 | "phf_shared", 1580 | "precomputed-hash", 1581 | "serde", 1582 | "string_cache_codegen", 1583 | "string_cache_shared", 1584 | ] 1585 | 1586 | [[package]] 1587 | name = "string_cache_codegen" 1588 | version = "0.4.4" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6" 1591 | dependencies = [ 1592 | "phf_generator", 1593 | "phf_shared", 1594 | "proc-macro2 1.0.86", 1595 | "quote 1.0.36", 1596 | "string_cache_shared", 1597 | ] 1598 | 1599 | [[package]] 1600 | name = "string_cache_shared" 1601 | version = "0.3.0" 1602 | source = "registry+https://github.com/rust-lang/crates.io-index" 1603 | checksum = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" 1604 | 1605 | [[package]] 1606 | name = "strsim" 1607 | version = "0.11.1" 1608 | source = "registry+https://github.com/rust-lang/crates.io-index" 1609 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1610 | 1611 | [[package]] 1612 | name = "subtle" 1613 | version = "2.6.1" 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" 1615 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1616 | 1617 | [[package]] 1618 | name = "syn" 1619 | version = "0.15.44" 1620 | source = "registry+https://github.com/rust-lang/crates.io-index" 1621 | checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" 1622 | dependencies = [ 1623 | "proc-macro2 0.4.30", 1624 | "quote 0.6.13", 1625 | "unicode-xid", 1626 | ] 1627 | 1628 | [[package]] 1629 | name = "syn" 1630 | version = "2.0.71" 1631 | source = "registry+https://github.com/rust-lang/crates.io-index" 1632 | checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" 1633 | dependencies = [ 1634 | "proc-macro2 1.0.86", 1635 | "quote 1.0.36", 1636 | "unicode-ident", 1637 | ] 1638 | 1639 | [[package]] 1640 | name = "sync_wrapper" 1641 | version = "1.0.1" 1642 | source = "registry+https://github.com/rust-lang/crates.io-index" 1643 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 1644 | 1645 | [[package]] 1646 | name = "system-configuration" 1647 | version = "0.5.1" 1648 | source = "registry+https://github.com/rust-lang/crates.io-index" 1649 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 1650 | dependencies = [ 1651 | "bitflags 1.3.2", 1652 | "core-foundation", 1653 | "system-configuration-sys", 1654 | ] 1655 | 1656 | [[package]] 1657 | name = "system-configuration-sys" 1658 | version = "0.5.0" 1659 | source = "registry+https://github.com/rust-lang/crates.io-index" 1660 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 1661 | dependencies = [ 1662 | "core-foundation-sys", 1663 | "libc", 1664 | ] 1665 | 1666 | [[package]] 1667 | name = "tavern_card_tools" 1668 | version = "0.1.4" 1669 | dependencies = [ 1670 | "anyhow", 1671 | "base64", 1672 | "bytes", 1673 | "chrono", 1674 | "clap", 1675 | "env_logger", 1676 | "image", 1677 | "log", 1678 | "png", 1679 | "reqwest", 1680 | "serde", 1681 | "serde-transcode", 1682 | "serde_json", 1683 | "serde_path_to_error", 1684 | "soup", 1685 | "test-context", 1686 | "textwrap", 1687 | ] 1688 | 1689 | [[package]] 1690 | name = "tempfile" 1691 | version = "3.10.1" 1692 | source = "registry+https://github.com/rust-lang/crates.io-index" 1693 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 1694 | dependencies = [ 1695 | "cfg-if", 1696 | "fastrand", 1697 | "rustix 0.38.34", 1698 | "windows-sys 0.52.0", 1699 | ] 1700 | 1701 | [[package]] 1702 | name = "tendril" 1703 | version = "0.4.3" 1704 | source = "registry+https://github.com/rust-lang/crates.io-index" 1705 | checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" 1706 | dependencies = [ 1707 | "futf", 1708 | "mac", 1709 | "utf-8", 1710 | ] 1711 | 1712 | [[package]] 1713 | name = "terminal_size" 1714 | version = "0.2.6" 1715 | source = "registry+https://github.com/rust-lang/crates.io-index" 1716 | checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" 1717 | dependencies = [ 1718 | "rustix 0.37.27", 1719 | "windows-sys 0.48.0", 1720 | ] 1721 | 1722 | [[package]] 1723 | name = "test-context" 1724 | version = "0.3.0" 1725 | source = "registry+https://github.com/rust-lang/crates.io-index" 1726 | checksum = "6676ab8513edfd2601a108621103fdb45cac9098305ca25ec93f7023b06b05d9" 1727 | dependencies = [ 1728 | "futures", 1729 | "test-context-macros", 1730 | ] 1731 | 1732 | [[package]] 1733 | name = "test-context-macros" 1734 | version = "0.3.0" 1735 | source = "registry+https://github.com/rust-lang/crates.io-index" 1736 | checksum = "78ea17a2dc368aeca6f554343ced1b1e31f76d63683fa8016e5844bd7a5144a1" 1737 | dependencies = [ 1738 | "proc-macro2 1.0.86", 1739 | "quote 1.0.36", 1740 | "syn 2.0.71", 1741 | ] 1742 | 1743 | [[package]] 1744 | name = "textwrap" 1745 | version = "0.16.1" 1746 | source = "registry+https://github.com/rust-lang/crates.io-index" 1747 | checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" 1748 | dependencies = [ 1749 | "smawk", 1750 | "terminal_size", 1751 | "unicode-linebreak", 1752 | "unicode-width", 1753 | ] 1754 | 1755 | [[package]] 1756 | name = "tinyvec" 1757 | version = "1.8.0" 1758 | source = "registry+https://github.com/rust-lang/crates.io-index" 1759 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 1760 | dependencies = [ 1761 | "tinyvec_macros", 1762 | ] 1763 | 1764 | [[package]] 1765 | name = "tinyvec_macros" 1766 | version = "0.1.1" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1769 | 1770 | [[package]] 1771 | name = "tokio" 1772 | version = "1.38.1" 1773 | source = "registry+https://github.com/rust-lang/crates.io-index" 1774 | checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" 1775 | dependencies = [ 1776 | "backtrace", 1777 | "bytes", 1778 | "libc", 1779 | "mio", 1780 | "pin-project-lite", 1781 | "socket2", 1782 | "windows-sys 0.48.0", 1783 | ] 1784 | 1785 | [[package]] 1786 | name = "tokio-native-tls" 1787 | version = "0.3.1" 1788 | source = "registry+https://github.com/rust-lang/crates.io-index" 1789 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1790 | dependencies = [ 1791 | "native-tls", 1792 | "tokio", 1793 | ] 1794 | 1795 | [[package]] 1796 | name = "tokio-rustls" 1797 | version = "0.26.0" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" 1800 | dependencies = [ 1801 | "rustls", 1802 | "rustls-pki-types", 1803 | "tokio", 1804 | ] 1805 | 1806 | [[package]] 1807 | name = "tokio-util" 1808 | version = "0.7.11" 1809 | source = "registry+https://github.com/rust-lang/crates.io-index" 1810 | checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" 1811 | dependencies = [ 1812 | "bytes", 1813 | "futures-core", 1814 | "futures-sink", 1815 | "pin-project-lite", 1816 | "tokio", 1817 | ] 1818 | 1819 | [[package]] 1820 | name = "tower" 1821 | version = "0.4.13" 1822 | source = "registry+https://github.com/rust-lang/crates.io-index" 1823 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 1824 | dependencies = [ 1825 | "futures-core", 1826 | "futures-util", 1827 | "pin-project", 1828 | "pin-project-lite", 1829 | "tokio", 1830 | "tower-layer", 1831 | "tower-service", 1832 | ] 1833 | 1834 | [[package]] 1835 | name = "tower-layer" 1836 | version = "0.3.2" 1837 | source = "registry+https://github.com/rust-lang/crates.io-index" 1838 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 1839 | 1840 | [[package]] 1841 | name = "tower-service" 1842 | version = "0.3.2" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1845 | 1846 | [[package]] 1847 | name = "tracing" 1848 | version = "0.1.40" 1849 | source = "registry+https://github.com/rust-lang/crates.io-index" 1850 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 1851 | dependencies = [ 1852 | "pin-project-lite", 1853 | "tracing-core", 1854 | ] 1855 | 1856 | [[package]] 1857 | name = "tracing-core" 1858 | version = "0.1.32" 1859 | source = "registry+https://github.com/rust-lang/crates.io-index" 1860 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 1861 | dependencies = [ 1862 | "once_cell", 1863 | ] 1864 | 1865 | [[package]] 1866 | name = "try-lock" 1867 | version = "0.2.5" 1868 | source = "registry+https://github.com/rust-lang/crates.io-index" 1869 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1870 | 1871 | [[package]] 1872 | name = "unicase" 1873 | version = "2.7.0" 1874 | source = "registry+https://github.com/rust-lang/crates.io-index" 1875 | checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" 1876 | dependencies = [ 1877 | "version_check", 1878 | ] 1879 | 1880 | [[package]] 1881 | name = "unicode-bidi" 1882 | version = "0.3.15" 1883 | source = "registry+https://github.com/rust-lang/crates.io-index" 1884 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 1885 | 1886 | [[package]] 1887 | name = "unicode-ident" 1888 | version = "1.0.12" 1889 | source = "registry+https://github.com/rust-lang/crates.io-index" 1890 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1891 | 1892 | [[package]] 1893 | name = "unicode-linebreak" 1894 | version = "0.1.5" 1895 | source = "registry+https://github.com/rust-lang/crates.io-index" 1896 | checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" 1897 | 1898 | [[package]] 1899 | name = "unicode-normalization" 1900 | version = "0.1.23" 1901 | source = "registry+https://github.com/rust-lang/crates.io-index" 1902 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 1903 | dependencies = [ 1904 | "tinyvec", 1905 | ] 1906 | 1907 | [[package]] 1908 | name = "unicode-width" 1909 | version = "0.1.13" 1910 | source = "registry+https://github.com/rust-lang/crates.io-index" 1911 | checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" 1912 | 1913 | [[package]] 1914 | name = "unicode-xid" 1915 | version = "0.1.0" 1916 | source = "registry+https://github.com/rust-lang/crates.io-index" 1917 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1918 | 1919 | [[package]] 1920 | name = "untrusted" 1921 | version = "0.9.0" 1922 | source = "registry+https://github.com/rust-lang/crates.io-index" 1923 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1924 | 1925 | [[package]] 1926 | name = "url" 1927 | version = "2.5.2" 1928 | source = "registry+https://github.com/rust-lang/crates.io-index" 1929 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 1930 | dependencies = [ 1931 | "form_urlencoded", 1932 | "idna", 1933 | "percent-encoding", 1934 | ] 1935 | 1936 | [[package]] 1937 | name = "utf-8" 1938 | version = "0.7.6" 1939 | source = "registry+https://github.com/rust-lang/crates.io-index" 1940 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1941 | 1942 | [[package]] 1943 | name = "utf8parse" 1944 | version = "0.2.2" 1945 | source = "registry+https://github.com/rust-lang/crates.io-index" 1946 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1947 | 1948 | [[package]] 1949 | name = "vcpkg" 1950 | version = "0.2.15" 1951 | source = "registry+https://github.com/rust-lang/crates.io-index" 1952 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1953 | 1954 | [[package]] 1955 | name = "version_check" 1956 | version = "0.9.4" 1957 | source = "registry+https://github.com/rust-lang/crates.io-index" 1958 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1959 | 1960 | [[package]] 1961 | name = "want" 1962 | version = "0.3.1" 1963 | source = "registry+https://github.com/rust-lang/crates.io-index" 1964 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1965 | dependencies = [ 1966 | "try-lock", 1967 | ] 1968 | 1969 | [[package]] 1970 | name = "wasi" 1971 | version = "0.11.0+wasi-snapshot-preview1" 1972 | source = "registry+https://github.com/rust-lang/crates.io-index" 1973 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1974 | 1975 | [[package]] 1976 | name = "wasm-bindgen" 1977 | version = "0.2.92" 1978 | source = "registry+https://github.com/rust-lang/crates.io-index" 1979 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 1980 | dependencies = [ 1981 | "cfg-if", 1982 | "wasm-bindgen-macro", 1983 | ] 1984 | 1985 | [[package]] 1986 | name = "wasm-bindgen-backend" 1987 | version = "0.2.92" 1988 | source = "registry+https://github.com/rust-lang/crates.io-index" 1989 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 1990 | dependencies = [ 1991 | "bumpalo", 1992 | "log", 1993 | "once_cell", 1994 | "proc-macro2 1.0.86", 1995 | "quote 1.0.36", 1996 | "syn 2.0.71", 1997 | "wasm-bindgen-shared", 1998 | ] 1999 | 2000 | [[package]] 2001 | name = "wasm-bindgen-futures" 2002 | version = "0.4.42" 2003 | source = "registry+https://github.com/rust-lang/crates.io-index" 2004 | checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" 2005 | dependencies = [ 2006 | "cfg-if", 2007 | "js-sys", 2008 | "wasm-bindgen", 2009 | "web-sys", 2010 | ] 2011 | 2012 | [[package]] 2013 | name = "wasm-bindgen-macro" 2014 | version = "0.2.92" 2015 | source = "registry+https://github.com/rust-lang/crates.io-index" 2016 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 2017 | dependencies = [ 2018 | "quote 1.0.36", 2019 | "wasm-bindgen-macro-support", 2020 | ] 2021 | 2022 | [[package]] 2023 | name = "wasm-bindgen-macro-support" 2024 | version = "0.2.92" 2025 | source = "registry+https://github.com/rust-lang/crates.io-index" 2026 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 2027 | dependencies = [ 2028 | "proc-macro2 1.0.86", 2029 | "quote 1.0.36", 2030 | "syn 2.0.71", 2031 | "wasm-bindgen-backend", 2032 | "wasm-bindgen-shared", 2033 | ] 2034 | 2035 | [[package]] 2036 | name = "wasm-bindgen-shared" 2037 | version = "0.2.92" 2038 | source = "registry+https://github.com/rust-lang/crates.io-index" 2039 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 2040 | 2041 | [[package]] 2042 | name = "web-sys" 2043 | version = "0.3.69" 2044 | source = "registry+https://github.com/rust-lang/crates.io-index" 2045 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 2046 | dependencies = [ 2047 | "js-sys", 2048 | "wasm-bindgen", 2049 | ] 2050 | 2051 | [[package]] 2052 | name = "weezl" 2053 | version = "0.1.8" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" 2056 | 2057 | [[package]] 2058 | name = "winapi" 2059 | version = "0.3.9" 2060 | source = "registry+https://github.com/rust-lang/crates.io-index" 2061 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2062 | dependencies = [ 2063 | "winapi-i686-pc-windows-gnu", 2064 | "winapi-x86_64-pc-windows-gnu", 2065 | ] 2066 | 2067 | [[package]] 2068 | name = "winapi-i686-pc-windows-gnu" 2069 | version = "0.4.0" 2070 | source = "registry+https://github.com/rust-lang/crates.io-index" 2071 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2072 | 2073 | [[package]] 2074 | name = "winapi-x86_64-pc-windows-gnu" 2075 | version = "0.4.0" 2076 | source = "registry+https://github.com/rust-lang/crates.io-index" 2077 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2078 | 2079 | [[package]] 2080 | name = "windows-core" 2081 | version = "0.52.0" 2082 | source = "registry+https://github.com/rust-lang/crates.io-index" 2083 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 2084 | dependencies = [ 2085 | "windows-targets 0.52.6", 2086 | ] 2087 | 2088 | [[package]] 2089 | name = "windows-sys" 2090 | version = "0.48.0" 2091 | source = "registry+https://github.com/rust-lang/crates.io-index" 2092 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2093 | dependencies = [ 2094 | "windows-targets 0.48.5", 2095 | ] 2096 | 2097 | [[package]] 2098 | name = "windows-sys" 2099 | version = "0.52.0" 2100 | source = "registry+https://github.com/rust-lang/crates.io-index" 2101 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2102 | dependencies = [ 2103 | "windows-targets 0.52.6", 2104 | ] 2105 | 2106 | [[package]] 2107 | name = "windows-targets" 2108 | version = "0.48.5" 2109 | source = "registry+https://github.com/rust-lang/crates.io-index" 2110 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2111 | dependencies = [ 2112 | "windows_aarch64_gnullvm 0.48.5", 2113 | "windows_aarch64_msvc 0.48.5", 2114 | "windows_i686_gnu 0.48.5", 2115 | "windows_i686_msvc 0.48.5", 2116 | "windows_x86_64_gnu 0.48.5", 2117 | "windows_x86_64_gnullvm 0.48.5", 2118 | "windows_x86_64_msvc 0.48.5", 2119 | ] 2120 | 2121 | [[package]] 2122 | name = "windows-targets" 2123 | version = "0.52.6" 2124 | source = "registry+https://github.com/rust-lang/crates.io-index" 2125 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2126 | dependencies = [ 2127 | "windows_aarch64_gnullvm 0.52.6", 2128 | "windows_aarch64_msvc 0.52.6", 2129 | "windows_i686_gnu 0.52.6", 2130 | "windows_i686_gnullvm", 2131 | "windows_i686_msvc 0.52.6", 2132 | "windows_x86_64_gnu 0.52.6", 2133 | "windows_x86_64_gnullvm 0.52.6", 2134 | "windows_x86_64_msvc 0.52.6", 2135 | ] 2136 | 2137 | [[package]] 2138 | name = "windows_aarch64_gnullvm" 2139 | version = "0.48.5" 2140 | source = "registry+https://github.com/rust-lang/crates.io-index" 2141 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2142 | 2143 | [[package]] 2144 | name = "windows_aarch64_gnullvm" 2145 | version = "0.52.6" 2146 | source = "registry+https://github.com/rust-lang/crates.io-index" 2147 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2148 | 2149 | [[package]] 2150 | name = "windows_aarch64_msvc" 2151 | version = "0.48.5" 2152 | source = "registry+https://github.com/rust-lang/crates.io-index" 2153 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2154 | 2155 | [[package]] 2156 | name = "windows_aarch64_msvc" 2157 | version = "0.52.6" 2158 | source = "registry+https://github.com/rust-lang/crates.io-index" 2159 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2160 | 2161 | [[package]] 2162 | name = "windows_i686_gnu" 2163 | version = "0.48.5" 2164 | source = "registry+https://github.com/rust-lang/crates.io-index" 2165 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2166 | 2167 | [[package]] 2168 | name = "windows_i686_gnu" 2169 | version = "0.52.6" 2170 | source = "registry+https://github.com/rust-lang/crates.io-index" 2171 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2172 | 2173 | [[package]] 2174 | name = "windows_i686_gnullvm" 2175 | version = "0.52.6" 2176 | source = "registry+https://github.com/rust-lang/crates.io-index" 2177 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2178 | 2179 | [[package]] 2180 | name = "windows_i686_msvc" 2181 | version = "0.48.5" 2182 | source = "registry+https://github.com/rust-lang/crates.io-index" 2183 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2184 | 2185 | [[package]] 2186 | name = "windows_i686_msvc" 2187 | version = "0.52.6" 2188 | source = "registry+https://github.com/rust-lang/crates.io-index" 2189 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2190 | 2191 | [[package]] 2192 | name = "windows_x86_64_gnu" 2193 | version = "0.48.5" 2194 | source = "registry+https://github.com/rust-lang/crates.io-index" 2195 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2196 | 2197 | [[package]] 2198 | name = "windows_x86_64_gnu" 2199 | version = "0.52.6" 2200 | source = "registry+https://github.com/rust-lang/crates.io-index" 2201 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2202 | 2203 | [[package]] 2204 | name = "windows_x86_64_gnullvm" 2205 | version = "0.48.5" 2206 | source = "registry+https://github.com/rust-lang/crates.io-index" 2207 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2208 | 2209 | [[package]] 2210 | name = "windows_x86_64_gnullvm" 2211 | version = "0.52.6" 2212 | source = "registry+https://github.com/rust-lang/crates.io-index" 2213 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2214 | 2215 | [[package]] 2216 | name = "windows_x86_64_msvc" 2217 | version = "0.48.5" 2218 | source = "registry+https://github.com/rust-lang/crates.io-index" 2219 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2220 | 2221 | [[package]] 2222 | name = "windows_x86_64_msvc" 2223 | version = "0.52.6" 2224 | source = "registry+https://github.com/rust-lang/crates.io-index" 2225 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2226 | 2227 | [[package]] 2228 | name = "winreg" 2229 | version = "0.52.0" 2230 | source = "registry+https://github.com/rust-lang/crates.io-index" 2231 | checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" 2232 | dependencies = [ 2233 | "cfg-if", 2234 | "windows-sys 0.48.0", 2235 | ] 2236 | 2237 | [[package]] 2238 | name = "zeroize" 2239 | version = "1.8.1" 2240 | source = "registry+https://github.com/rust-lang/crates.io-index" 2241 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2242 | 2243 | [[package]] 2244 | name = "zune-core" 2245 | version = "0.4.12" 2246 | source = "registry+https://github.com/rust-lang/crates.io-index" 2247 | checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" 2248 | 2249 | [[package]] 2250 | name = "zune-jpeg" 2251 | version = "0.4.11" 2252 | source = "registry+https://github.com/rust-lang/crates.io-index" 2253 | checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" 2254 | dependencies = [ 2255 | "zune-core", 2256 | ] 2257 | --------------------------------------------------------------------------------