├── .travis.yml ├── examples ├── cookie ├── day01.rs └── day02.rs ├── aocf_cli ├── .gitignore ├── src │ ├── lib.rs │ ├── conf.rs │ ├── pretty.rs │ ├── cli.rs │ └── bin │ │ └── aocf.rs ├── docker.nix ├── aocf_cli.nix ├── COPYING ├── Cargo.toml ├── README.md └── Cargo.lock ├── demo.gif ├── cookie.png ├── .gitignore ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ ├── check.yml │ ├── windows-build.yml │ ├── osx-build.yml │ ├── test.yml │ ├── clippy-annotate.yml │ └── release.yml ├── default.nix ├── src ├── cli.rs ├── cookie │ ├── db_schema.rs │ └── db_models.rs ├── cookie.rs ├── http.rs └── lib.rs ├── .gitjournal.toml ├── stable.nix ├── bump.sh ├── cookie.md ├── COPYING ├── Cargo.toml ├── CHANGELOG.md └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | cache: cargo 3 | -------------------------------------------------------------------------------- /examples/cookie: -------------------------------------------------------------------------------- 1 | yoursessioncookiedatagoeshere 2 | -------------------------------------------------------------------------------- /aocf_cli/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | *.sw* 4 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxeh/aocf/HEAD/demo.gif -------------------------------------------------------------------------------- /cookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxeh/aocf/HEAD/cookie.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | *.sw* 4 | /aoc_cli/target 5 | /Cargo.lock 6 | -------------------------------------------------------------------------------- /aocf_cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate failure; 2 | #[macro_use] extern crate serde_derive; 3 | 4 | pub mod conf; 5 | pub mod pretty; 6 | pub mod cli; 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | with import {}; 2 | 3 | stdenv.mkDerivation { 4 | name = "aocf"; 5 | 6 | buildInputs = [ 7 | rustc 8 | cargo 9 | pkg-config 10 | openssl 11 | sqlite 12 | ]; 13 | } 14 | -------------------------------------------------------------------------------- /aocf_cli/docker.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import {} }: 2 | 3 | let 4 | aocf_cli = pkgs.callPackage ./aocf_cli.nix {}; 5 | in 6 | pkgs.dockerTools.buildImage { 7 | name = "aocf"; 8 | config = { 9 | Cmd = [ "${aocf_cli}/bin/aocf" ]; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use std::path::PathBuf; 3 | 4 | #[derive(Parser, Debug)] 5 | #[clap(about = "Advent of Code problem\n")] 6 | pub struct AocOpts { 7 | /// File to read as input 8 | pub input: Option, 9 | } 10 | 11 | -------------------------------------------------------------------------------- /.gitjournal.toml: -------------------------------------------------------------------------------- 1 | categories = ["Added", "Changed", "Fixed", "Improved", "Removed"] 2 | category_delimiters = ["[", "]"] 3 | colored_output = false 4 | enable_debug = true 5 | excluded_commit_tags = [] 6 | enable_footers = false 7 | show_commit_hash = true 8 | show_prefix = false 9 | sort_by = "date" 10 | template_prefix = "" 11 | -------------------------------------------------------------------------------- /examples/day01.rs: -------------------------------------------------------------------------------- 1 | extern crate aocf; 2 | 3 | use aocf::Aoc; 4 | 5 | fn main() { 6 | let mut aoc = Aoc::new() 7 | .year(Some(2019)) 8 | .day(Some(1)) 9 | .cookie_file("./examples/cookie") 10 | .init() 11 | .unwrap(); 12 | 13 | let input = if let Ok(i) = aoc.get_input(false) { 14 | i 15 | } else { 16 | "you probably need to add a valid cookie".to_string() 17 | }; 18 | 19 | println!("{}", input); 20 | } 21 | -------------------------------------------------------------------------------- /examples/day02.rs: -------------------------------------------------------------------------------- 1 | extern crate aocf; 2 | 3 | use aocf::Aoc; 4 | 5 | fn main() { 6 | let mut aoc = Aoc::new() 7 | .year(Some(2019)) 8 | .day(Some(2)) 9 | .cookie("yoursessioncookiedatagoeshere") 10 | .init() 11 | .unwrap(); 12 | 13 | let input = if let Ok(i) = aoc.get_input(false) { 14 | i 15 | } else { 16 | "you probably need to add a valid cookie".to_string() 17 | }; 18 | 19 | println!("{}", input); 20 | } 21 | -------------------------------------------------------------------------------- /src/cookie/db_schema.rs: -------------------------------------------------------------------------------- 1 | table! { 2 | moz_cookies (id) { 3 | id -> Integer, 4 | originAttributes -> Text, 5 | name -> Text, 6 | value -> Text, 7 | host -> Text, 8 | path -> Text, 9 | expiry -> Integer, 10 | lastAccessed -> Integer, 11 | creationTime -> Integer, 12 | isSecure -> Integer, 13 | isHttpOnly -> Integer, 14 | inBrowserElement -> Integer, 15 | sameSite -> Integer, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions-rs/toolchain@v1 13 | with: 14 | profile: minimal 15 | toolchain: stable 16 | components: clippy 17 | override: true 18 | - name: Install dependencies 19 | run: sudo apt-get install -y libsqlite3-dev 20 | - name: Build 21 | run: cargo build --verbose 22 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: check 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions-rs/toolchain@v1 13 | with: 14 | toolchain: stable 15 | components: clippy 16 | override: true 17 | - name: Install dependencies 18 | run: sudo apt-get install -y libsqlite3-dev 19 | - name: Run cargo-check 20 | run: | 21 | cargo install cargo-check 22 | cargo check --verbose 23 | -------------------------------------------------------------------------------- /.github/workflows/windows-build.yml: -------------------------------------------------------------------------------- 1 | name: windows 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: windows-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - uses: actions-rs/toolchain@v1 14 | with: 15 | profile: minimal 16 | toolchain: stable 17 | override: true 18 | 19 | - name: Build 20 | run: cargo build --verbose 21 | 22 | - name: Build tests 23 | run: cargo test --verbose --no-run 24 | 25 | - name: Run tests 26 | run: cargo test --verbose 27 | -------------------------------------------------------------------------------- /stable.nix: -------------------------------------------------------------------------------- 1 | # Use latest stable Rust 2 | # 3 | # To use, clone the Mozilla overlay, and provide the path at nix-shell 4 | # invocation, e.g.: 5 | # 6 | # git clone https://github.com/mozilla/nixpkgs-mozilla.git 7 | # nix-shell stable.nix -I rustoverlay=/path/to/overlay 8 | 9 | with import {}; 10 | with import pkgs pkgs; 11 | 12 | stdenv.mkDerivation { 13 | name = "aocf"; 14 | 15 | buildInputs = [ 16 | latest.rustChannels.stable.rust 17 | pkgconfig 18 | openssl 19 | sqlite 20 | ]; 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/osx-build.yml: -------------------------------------------------------------------------------- 1 | name: macOS 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: macos-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - uses: actions-rs/toolchain@v1 14 | with: 15 | profile: minimal 16 | toolchain: stable 17 | override: true 18 | 19 | - name: Install dependencies 20 | run: brew install sqlite3 21 | 22 | - name: Build 23 | run: cargo build --verbose 24 | 25 | - name: Build tests 26 | run: cargo test --verbose --no-run 27 | 28 | - name: Run tests 29 | run: cargo test --verbose 30 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions-rs/toolchain@v1 13 | with: 14 | profile: minimal 15 | toolchain: stable 16 | components: clippy 17 | override: true 18 | - name: Install dependencies 19 | run: sudo apt-get install -y libsqlite3-dev 20 | - name: Build tests 21 | run: cargo test --verbose --no-run 22 | - name: Run tests 23 | run: cargo test --verbose --no-fail-fast -- --test-threads=1 24 | -------------------------------------------------------------------------------- /bump.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | FROM=$1 4 | TO=$2 5 | 6 | if ! grep "version = \"$FROM\"" Cargo.toml &> /dev/null; then 7 | echo "\"$FROM\" doesn't seem to be a valid version." 8 | exit 1 9 | fi 10 | 11 | sed -i "s/version = \"$FROM\"/version = \"$TO\"/" Cargo.toml 12 | sed -i "s/version = \"$FROM\"/version = \"$TO\"/" aocf_cli/Cargo.toml 13 | 14 | cargo build || exit 15 | cd aocf_cli 16 | cargo build || exit 17 | 18 | # requires `git-journal` -> `cargo install git-journal` 19 | #git journal -o CHANGELOG.md 20 | 21 | cd .. 22 | git commit Cargo.toml aocf_cli/Cargo.toml aocf_cli/Cargo.lock CHANGELOG.md -m "Bump v$FROM → v$TO" 23 | git tag "v$TO" 24 | -------------------------------------------------------------------------------- /cookie.md: -------------------------------------------------------------------------------- 1 | # AoC session cookie 2 | 3 | To be able to retrieve personal input, and submit solutions, you need the 4 | contents of your personal session cookie. 5 | 6 | ## Firefox 7 | 8 | The `aocf` CLI can obtain this directly from the Firefox cookie store using 9 | the `get-cookie` command, after previously logging in to Advent of Code using 10 | Firefox. 11 | 12 | To get the value manually, use "Storage Inspector" from the "Web Developer" 13 | menu, and copy the value of the cookie named "session". 14 | 15 | ## Chrome 16 | 17 | * Hit Ctrl-Shift-I for developer tools. 18 | * Copy the "session" cookie text from the Application tab, as shown below: 19 | 20 | ![](cookie.png) 21 | -------------------------------------------------------------------------------- /.github/workflows/clippy-annotate.yml: -------------------------------------------------------------------------------- 1 | name: clippy 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions-rs/toolchain@v1 13 | with: 14 | toolchain: stable 15 | components: clippy 16 | override: true 17 | - name: Install dependencies 18 | run: sudo apt-get install -y libsqlite3-dev 19 | - uses: actions-rs/clippy-check@v1 20 | with: 21 | token: ${{ secrets.GITHUB_TOKEN }} 22 | args: --all-features -- -D warnings 23 | - name: Run clippy 24 | run: cargo clippy --all-features -- -D warnings 25 | -------------------------------------------------------------------------------- /aocf_cli/aocf_cli.nix: -------------------------------------------------------------------------------- 1 | # this will no longer build, since it requires a non-path `aocf` dependency to build 2 | 3 | { stdenv 4 | , lib 5 | , rustPlatform 6 | , pkg-config 7 | , openssl 8 | }: 9 | 10 | rustPlatform.buildRustPackage rec { 11 | pname = "aocf_cli"; 12 | version = "0.1.8"; 13 | src = ./.; 14 | cargoSha256 = "1d2m4jyf4b5mh2carms77m78cgakw5h3hwhmzrhj974y87599hy1"; 15 | 16 | nativeBuildInputs = [ pkg-config ]; 17 | 18 | buildInputs = [ 19 | openssl 20 | ]; 21 | 22 | meta = with lib; { 23 | description = "Advent of Code Swiss army knife"; 24 | homepage = "https://github.com/nuxeh/aocf"; 25 | license = licenses.isc; 26 | maintainers = with maintainers; [ edcragg ]; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Edward Cragg 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 9 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 11 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 12 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 13 | PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /aocf_cli/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Edward Cragg 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 9 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 11 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 12 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 13 | PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /src/cookie/db_models.rs: -------------------------------------------------------------------------------- 1 | /* 2 | PRAGMA table_info(moz_cookies) 3 | 0|id|INTEGER|0||1 4 | 2|originAttributes|TEXT|1|''|0 5 | 3|name|TEXT|0||0 6 | 4|value|TEXT|0||0 7 | 5|host|TEXT|0||0 8 | 6|path|TEXT|0||0 9 | 7|expiry|INTEGER|0||0 10 | 8|lastAccessed|INTEGER|0||0 11 | 9|creationTime|INTEGER|0||0 12 | 10|isSecure|INTEGER|0||0 13 | 11|isHttpOnly|INTEGER|0||0 14 | 12|inBrowserElement|INTEGER|0|0|0 15 | 13|sameSite|INTEGER|0|0|0 16 | */ 17 | 18 | #[allow(non_snake_case)] 19 | #[derive(Queryable, Debug)] 20 | pub struct FirefoxCookie { 21 | pub id: i32, 22 | pub originAttributes: String, 23 | pub name: String, 24 | pub value: String, 25 | pub host: String, 26 | pub path: String, 27 | pub expiry: i32, 28 | pub lastAccessed: i32, 29 | pub creationTime: i32, 30 | pub isSecure: i32, 31 | pub isHttpOnly: i32, 32 | pub inBrowserElement: i32, 33 | pub sameSite: i32, 34 | } 35 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "aocf" 3 | version = "0.1.21" 4 | authors = ["Ed Cragg "] 5 | edition = "2018" 6 | license = "ISC" 7 | readme = "README.md" 8 | description = "A crate and CLI helper tool for Advent of Code" 9 | repository = "https://github.com/nuxeh/aocf" 10 | keywords = ["advent", "code", "cli", "tool", "helper"] 11 | 12 | [dependencies] 13 | diesel = { version = "1.4.5", features = ["sqlite"], optional = true } 14 | failure = "0.1.8" 15 | html2md = { version = "0.2.10", optional = true } 16 | regex = "1.4.2" 17 | serde = "1.0.117" 18 | serde_derive = "1.0.117" 19 | serde_json = "1.0.59" 20 | tempfile = "3.1.0" 21 | libsqlite3-sys = { version = ">=0.8.0, <0.21.0", features = ["min_sqlite_version_3_7_16", "bundled"], optional = true } 22 | clap = { version = "4.0", features = ["derive"] } 23 | atty = "0.2.14" 24 | ureq = "2.2.0" 25 | 26 | [features] 27 | sqlite = ["diesel", "libsqlite3-sys"] 28 | html_parsing = ["html2md"] 29 | default = [] 30 | -------------------------------------------------------------------------------- /aocf_cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "aocf_cli" 3 | version = "0.1.21" 4 | authors = ["Ed Cragg "] 5 | edition = "2018" 6 | license = "ISC" 7 | readme = "README.md" 8 | description = "CLI helper tool for Advent of Code, with a workflow similar to Git" 9 | repository = "https://github.com/nuxeh/aocf" 10 | keywords = ["advent", "code", "cli", "tool", "helper"] 11 | 12 | [[bin]] 13 | name = "aocf" 14 | 15 | [dev-dependencies] 16 | tempfile = "3.1.0" 17 | 18 | [dependencies] 19 | aocf = { path = "..", version = "0.1.15", features = ["sqlite", "html_parsing"] } 20 | chrono = "0.4.19" 21 | dirs = "3.0.1" 22 | failure = "0.1.8" 23 | serde = "1.0.117" 24 | serde_derive = "1.0.117" 25 | tempfile = "3.1.0" 26 | toml = "0.5.7" 27 | glob = "0.3.0" 28 | termimad = "0.9.1" 29 | crossterm = "0.17.7" 30 | regex = "1.4.2" 31 | clap = { version = "3.1", features = ["derive"] } 32 | clap_complete = "3.1" 33 | webbrowser = "0.5.5" 34 | 35 | [package.metadata.deb] 36 | extended-description = """\ 37 | Advent of Code fetch CLI tool modelled after Git. 38 | """ 39 | -------------------------------------------------------------------------------- /src/cookie.rs: -------------------------------------------------------------------------------- 1 | mod db_models; 2 | mod db_schema; 3 | 4 | use diesel::prelude::*; 5 | use diesel::sqlite::SqliteConnection; 6 | use failure::{Error, bail}; 7 | use std::path::Path; 8 | 9 | use db_models::*; 10 | use db_schema::*; 11 | 12 | fn connect_sqlite(path: impl AsRef) -> Result { 13 | let path = match path.as_ref().to_str() { 14 | Some(p) => p, 15 | None => bail!("can't parse path to string"), 16 | }; 17 | let connection = SqliteConnection::establish(path)?; 18 | Ok(connection) 19 | } 20 | 21 | pub fn get_session_cookie(path: impl AsRef) -> Result { 22 | let connection = connect_sqlite(path)?; 23 | 24 | let records = moz_cookies::table 25 | .filter(moz_cookies::host.eq(".adventofcode.com")) 26 | .filter(moz_cookies::name.eq("session")) 27 | .limit(1) 28 | .load::(&connection)?; 29 | 30 | if records.is_empty() { 31 | bail!("no cookie found in the cookie store"); 32 | } else { 33 | Ok(records[0].value.to_owned()) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /aocf_cli/src/conf.rs: -------------------------------------------------------------------------------- 1 | use failure::Error; 2 | use std::collections::hash_map::DefaultHasher; 3 | use std::fs::{File, read_to_string}; 4 | use std::hash::{Hash, Hasher}; 5 | use std::io::Write; 6 | use std::path::Path; 7 | 8 | #[derive(Serialize, Deserialize, Debug, Hash)] 9 | enum ExecMode { 10 | Stdin, 11 | File, 12 | } 13 | 14 | #[derive(Serialize, Deserialize, Debug, Hash)] 15 | pub struct Conf { 16 | pub year: i32, 17 | pub day: u32, 18 | editor: String, 19 | pub pager: String, 20 | exec: Option, 21 | mode: Option, 22 | } 23 | 24 | impl Default for Conf { 25 | fn default() -> Self { 26 | Self { 27 | year: 2015, 28 | day: 1, 29 | editor: "vim".into(), 30 | pager: "less".into(), 31 | exec: None, 32 | mode: None, 33 | } 34 | } 35 | } 36 | 37 | impl Conf { 38 | pub fn load(path: impl AsRef) -> Result { 39 | let conf = read_to_string(path.as_ref())?; 40 | let conf: Self = toml::de::from_str(&conf)?; 41 | Ok(conf) 42 | } 43 | 44 | pub fn write(&self, path: impl AsRef) -> Result<(), Error> { 45 | let mut file = File::create(path)?; 46 | file.write_all(toml::ser::to_string(&self)?.as_bytes())?; 47 | Ok(()) 48 | } 49 | 50 | pub fn calc_hash(&self) -> u64 { 51 | let mut s = DefaultHasher::new(); 52 | self.hash(&mut s); 53 | s.finish() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v0.1.21 2 | 3 | - **Added** Identify the tool via User-Agent 4 | 5 | # v0.1.18 6 | 7 | - **Added** `--web` flag for `brief` subcommand 8 | 9 | # v0.1.17 10 | 11 | - **Added** feature to make html parsing optional 12 | - **Changed** `reqwest` for `ureq` as HTTP client library 13 | 14 | # v0.1.16 15 | 16 | - **Added** Shell code completion generation 17 | - **Fixed** some clippy warnings 18 | 19 | # v0.1.15 20 | 21 | - **Fixed** GitHub release workfow 22 | 23 | # v0.1.14 24 | 25 | - **Added** cache paths compatible with lexicographic sorting 26 | 27 | # v0.1.13 28 | 29 | - **Fixed** clippy warning 30 | 31 | # v0.1.12 32 | 33 | - **Added** `summary` subcommand 34 | - Gives a handy overview of all stars obtained. 35 | - **Added** printing of solutions for `aocf status` subcommand 36 | 37 | # v0.1.11 38 | 39 | - **Added** `--now` and `--day` flags to brief subcommand 40 | - **Added** `--day` and `--now` flags for fetch subcommand 41 | - Allows fetching a given day without checking out that day first, useful 42 | for peeking at a new problem, for example. 43 | - **Added** `git-journal` configuration 44 | - **Added** make diesel and sqlite optional dependencies behind sqlite feature 45 | - **Added** CLI parsing for input file to crate struct 46 | - This allows an alternative input file to be used rather than fetched 47 | input, useful for testing, or modifying the input. 48 | - **Added** buffering of input data from a pipe 49 | - Alternative input data can now be provided by piping it to the built 50 | binary implementing the Aoc stuct. 51 | 52 | # v0.1.10: 53 | 54 | - **Added** Parse CLI arguments with `structopt` rather than `docopt` 55 | - This vastly improves command line parsing, and gives help on any available 56 | subcommands. 57 | 58 | # v0.1.9: 59 | 60 | - **Fixed** a bug with long running commands 61 | - Previously, long-running commands such as `aocf {input, brief} {--view, 62 | --pretty}` could cause regressions in the cache state, if the cache was 63 | updated while they were open. 64 | -------------------------------------------------------------------------------- /aocf_cli/src/pretty.rs: -------------------------------------------------------------------------------- 1 | use crossterm::{ 2 | cursor::{ Hide, Show}, 3 | event::{ 4 | self, 5 | Event, 6 | KeyEvent, 7 | KeyCode::*, 8 | }, 9 | queue, 10 | terminal::{ 11 | self, 12 | Clear, 13 | ClearType, 14 | EnterAlternateScreen, 15 | LeaveAlternateScreen, 16 | }, 17 | style::{ 18 | Color::*, 19 | Attribute::*, 20 | }, 21 | }; 22 | use std::io::{stderr, Write}; 23 | use failure::Error; 24 | use termimad::{ 25 | MadSkin, MadView, Alignment, Area, CompoundStyle, 26 | }; 27 | 28 | fn view_area() -> Area { 29 | let mut area = Area::full_screen(); 30 | area.pad_for_max_width(120); 31 | area 32 | } 33 | 34 | fn run_pretty(skin: MadSkin, content: &str) -> Result<(), Error> { 35 | let mut w = stderr(); 36 | queue!(w, EnterAlternateScreen)?; 37 | terminal::enable_raw_mode()?; 38 | queue!(w, Hide)?; 39 | let mut view = MadView::from(content.to_owned(), view_area(), skin); 40 | loop { 41 | view.write_on(&mut w)?; 42 | w.flush()?; 43 | match event::read() { 44 | Ok(Event::Key(KeyEvent{code, ..})) => { 45 | match code { 46 | Up => view.try_scroll_lines(-1), 47 | Down => view.try_scroll_lines(1), 48 | PageUp => view.try_scroll_pages(-1), 49 | PageDown => view.try_scroll_pages(1), 50 | _ => break, 51 | } 52 | } 53 | Ok(Event::Resize(..)) => { 54 | queue!(w, Clear(ClearType::All))?; 55 | view.resize(&view_area()); 56 | } 57 | _ => {} 58 | } 59 | } 60 | terminal::disable_raw_mode()?; 61 | queue!(w, Show)?; 62 | queue!(w, LeaveAlternateScreen)?; 63 | w.flush()?; 64 | Ok(()) 65 | } 66 | 67 | fn make_skin() -> MadSkin { 68 | let mut skin = MadSkin::default(); 69 | skin.table.align = Alignment::Center; 70 | skin.set_headers_fg(AnsiValue(178)); 71 | skin.bold.set_fg(Yellow); 72 | skin.italic.overwrite_with(&CompoundStyle::with_attr(Bold)); 73 | skin.italic.set_fg(White); 74 | skin.scrollbar.thumb.set_fg(AnsiValue(178)); 75 | skin.code_block.align = Alignment::Center; 76 | skin.bullet.set_bg(Rgb{ r: 0x0f, g: 0x0f, b: 0x23 }); 77 | skin.set_global_bg(Rgb{ r: 0x0f, g: 0x0f, b: 0x23 }); 78 | //skin.inline_code.set_bg(Rgb{ r: 0x10, g: 0x10, b: 0x1a }); 79 | skin 80 | } 81 | 82 | pub fn make_pretty(content: &str) -> Result<(), Error> { 83 | let skin = make_skin(); 84 | run_pretty(skin, content) 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `aocf` - Advent of Code fetch 2 | 3 | [![build](https://github.com/nuxeh/aocf/workflows/build/badge.svg)](https://github.com/nuxeh/aocf/actions?query=branch%3Amaster+event%3Apush+workflow%3Abuild) 4 | [![test](https://github.com/nuxeh/aocf/workflows/tests/badge.svg)](https://github.com/nuxeh/aocf/actions?query=branch%3Amaster+event%3Apush+workflow%3Atests) 5 | [![clippy](https://github.com/nuxeh/aocf/workflows/clippy/badge.svg)](https://github.com/nuxeh/aocf/actions?query=branch%3Amaster+event%3Apush+workflow%3Aclippy) 6 | [![macOS](https://github.com/nuxeh/aocf/workflows/macOS/badge.svg)](https://github.com/nuxeh/aocf/actions?query=branch%3Amaster+event%3Apush+workflow%3AmacOS) 7 | [![windows](https://github.com/nuxeh/aocf/workflows/windows/badge.svg)](https://github.com/nuxeh/aocf/actions?query=branch%3Amaster+event%3Apush+workflow%3Awindows) 8 | [![coveralls](https://img.shields.io/coveralls/github/nuxeh/aocf/master)](https://coveralls.io/github/nuxeh/aocf?branch=master) 9 | [![crates.io](https://img.shields.io/crates/v/aocf)](https://crates.io/crates/aocf) 10 | [![crates.io](https://docs.rs/aocf/badge.svg)](https://docs.rs/aocf/) 11 | 12 | A CLI tool (and also crate) for [Advent of Code](https://adventofcode.com/). 13 | 14 | ![demo](demo.gif) 15 | 16 | Written in Rust, but the CLI should be useful for development in any language. 17 | 18 | To use directly within Rust, the crate may be used as follows, for getting input 19 | data for a task as a string: 20 | 21 | ```rust 22 | use aocf::Aoc; 23 | 24 | fn main() { 25 | let mut aoc = Aoc::new() 26 | .year(Some(2020)) 27 | .day(Some(1)) 28 | .init() 29 | .unwrap(); 30 | 31 | // Get input data (don't force) 32 | let input = aoc.get_input(false); 33 | 34 | if let Ok(i) = input { 35 | println!("{}", i); 36 | } 37 | } 38 | ``` 39 | 40 | Documentation for the `Aoc` structure can be found 41 | [here](https://docs.rs/aocf/latest/aocf/struct.Aoc.html). 42 | 43 | Downloaded data is cached as JSON and queried each time the `Aoc` is 44 | initialised, to avoid unecessary requests. 45 | 46 | The CLI has a workflow similar to Git, e.g. 47 | 48 | ``` 49 | $ aocf init 50 | $ aocf get-cookie # get cookie from firefox cookie store 51 | $ aocf set-cookie 52 | $ aocf checkout 1 2019 53 | $ aocf checkout --now 54 | $ aocf fetch 55 | $ aocf brief --pretty 56 | $ aocf input 57 | $ aocf status 58 | $ aocf submit 59 | ``` 60 | 61 | More details can be found in in the CLI's [readme](./aocf_cli/README.md). 62 | 63 | The CLI can be used even if you don't plan to solve problems in Rust, and the 64 | CLI and the crate can also be freely used together, so if there is a root 65 | configuration created by the CLI, the crate will find and use this, or else 66 | store cached data in the current directory. 67 | 68 | [How to get your session cookie](./cookie.md). This can be as easy as logging 69 | in to AoC with Firefox, and having the CLI extract the authentication token 70 | automatically. 71 | 72 | ## Installation 73 | 74 | [Install Rust](https://www.rust-lang.org/tools/install) 75 | 76 | Install `aocf`: 77 | 78 | - `cargo install aocf_cli`. 79 | - `cargo install --path .` from inside a cloned repository. 80 | - `cargo deb --install` from inside a cloned repository. 81 | 82 | ## Dependencies 83 | 84 | Depends on development packages for `openssl`, `sqlite` dependencies are bundled. 85 | -------------------------------------------------------------------------------- /aocf_cli/README.md: -------------------------------------------------------------------------------- 1 | # `aocf_cli` - Advent of Code fetch CLI 2 | 3 | [![crates.io](https://img.shields.io/crates/v/aocf_cli)](https://crates.io/crates/aocf_cli) 4 | 5 | A CLI helper tool for [Advent of Code](https://adventofcode.com/). 6 | 7 | This is a wrapper around the `aocf` crate, and freely interoperates with it if 8 | needed. 9 | 10 | ## Install 11 | 12 | ``` 13 | cargo install aocf_cli 14 | ``` 15 | 16 | Or from source: 17 | 18 | ``` 19 | git clone https://github.com/aocf 20 | cd aocf/aocf_cli 21 | cargo install --path . 22 | ``` 23 | 24 | The tool will now be available as `aocf` for the user who ran this command. The 25 | cargo binary install path provided after cargo completes may need to be added 26 | to your shell's `PATH` variable. 27 | 28 | ## Commands 29 | 30 | ### `init` 31 | 32 | Initialise an aocf repository, similar to how you would initialise a git 33 | repository. Data and configuration for aocf is kept in `./.aocf`. 34 | 35 | ### `set-cookie` 36 | 37 | Write the cookie into cache using provided session cookie string. 38 | 39 | ### `get-cookie` 40 | 41 | Extract your session cookie from the Firefox cookie store. You should have 42 | previously logged in to Advent of code using Firefox. This command will then 43 | set the cookie as with `set-cookie`. 44 | 45 | ### `checkout` 46 | 47 | Move to a given day, and optionally year. May be combined with `--now`. 48 | 49 | ### `fetch` 50 | 51 | Fetch input and brief for the current day. 52 | 53 | ### `brief` 54 | 55 | Show the brief for the currently checked out day. 56 | 57 | ### `input` 58 | 59 | Print the currently checked out day's input. 60 | 61 | ### `status` 62 | 63 | Show the current status (for the currently checked out day). 64 | 65 | ### `summary` 66 | 67 | Show a summary of all challenges which exist in the cache, and stars achieved, 68 | for a given challenge year. The year shown is either the currently checked out 69 | year, or the year provided by the `--year` command line option. 70 | 71 | ### `completion` 72 | 73 | Generate a shell completion script. 74 | Supported shells are Bash, Zsh, Fish, Powershell, Elvish. 75 | 76 | ### `help` 77 | 78 | Get help on command usage, for a given subcommand. 79 | 80 | ## Option flags 81 | 82 | ### Time based flags 83 | 84 | * `--now` 85 | * `--year` 86 | * `--day` 87 | 88 | These can be used to override the current day or year used when fetching, or 89 | other commands. Generally commands will get the day and year from the 90 | root configuration if it exists, and these are not provided. 91 | 92 | ### Viewing flags 93 | 94 | * `--view` 95 | 96 | If no flags are given, `aocf` will generally output content on standard output 97 | or stderr; if `--view` is provided, output will be piped to the pager programme 98 | specified in the root configuration (`.aocf/config`) as e.g. `pager = "less"`. 99 | 100 | * `--pretty` 101 | 102 | Only available for the `brief` subcommand, pretty formats the challenge brief 103 | in a similar format to viewing on the Advent of Code website, in a scrollable, 104 | pager fashion. 105 | 106 | * `--web` 107 | 108 | Only available for the `brief` subcommand, opens the brief in a web browser. 109 | 110 | ### Retrieval flags 111 | 112 | * `--force` 113 | 114 | This will force retrieval from the AoC site, even if a cache exists already for 115 | the current day/problem part. 116 | 117 | ### Cache 118 | 119 | The cache for data for each day is stored as JSON under `.aocf/cache`. 120 | -------------------------------------------------------------------------------- /src/http.rs: -------------------------------------------------------------------------------- 1 | use crate::Aoc; 2 | use failure::{Error, bail}; 3 | 4 | #[cfg(feature = "html_parsing")] 5 | use crate::Level; 6 | #[cfg(feature = "html_parsing")] 7 | use html2md::parse_html; 8 | #[cfg(feature = "html_parsing")] 9 | use regex::Regex; 10 | 11 | const BASE: &str = "https://adventofcode.com"; 12 | 13 | fn user_agent() -> String { 14 | let repo = env!("CARGO_PKG_REPOSITORY"); 15 | let version = env!("CARGO_PKG_VERSION"); 16 | let authors = env!("CARGO_PKG_AUTHORS"); 17 | 18 | format!("{}@{} by {}", repo, version, authors) 19 | } 20 | 21 | fn get_url(aoc: &Aoc) -> Result { 22 | let url = match (aoc.day, aoc.year) { 23 | (Some(d), Some(y)) => format!("{}/{}/day/{}", BASE, y, d), 24 | _ => bail!("day or year not set"), 25 | }; 26 | Ok(url) 27 | } 28 | 29 | fn get_content(aoc: &Aoc, suffix: &str) -> Result { 30 | let url = format!("{}{}", get_url(aoc)?, suffix); 31 | let cookie = format!("session={}", aoc.cookie); 32 | let user_agent = user_agent(); 33 | 34 | let input = ureq::get(&url) 35 | .set("COOKIE", &cookie) 36 | .set("User-Agent", &user_agent) 37 | .call()? 38 | .into_string()?; 39 | 40 | Ok(input) 41 | } 42 | 43 | #[cfg(feature = "html_parsing")] 44 | pub fn get_brief(aoc: &Aoc) -> Result<(String, String), Error> { 45 | let brief = get_content(aoc, "")?; 46 | let title = get_title(&brief).unwrap_or_default(); 47 | let brief = get_html_section(&brief, "main").unwrap_or_default(); 48 | let brief = parse_html(&brief); 49 | let num_lines = brief.lines().count(); 50 | let brief = brief.lines() 51 | .skip(2) 52 | .take(num_lines - 4) 53 | .map(|l| format!("{}\n", l)) 54 | .collect::() 55 | .trim() 56 | .to_string(); 57 | Ok((title, brief)) 58 | } 59 | 60 | pub fn get_input(aoc: &Aoc) -> Result { 61 | let input = get_content(aoc, "/input")?; 62 | Ok(input) 63 | } 64 | 65 | #[cfg(feature = "html_parsing")] 66 | pub fn submit(aoc: &Aoc, solution: &str) -> Result { 67 | let url = format!("{}/answer", get_url(aoc)?); 68 | let cookie = format!("session={}", aoc.cookie); 69 | let user_agent = user_agent(); 70 | 71 | let level = match aoc.level { 72 | Level::First => "1", 73 | Level::Second => "2", 74 | }; 75 | 76 | let resp = ureq::post(&url) 77 | .set("COOKIE", &cookie) 78 | .set("User-Agent", &user_agent) 79 | .send_form(&[ 80 | ("level", level), 81 | ("answer", solution), 82 | ])? 83 | .into_string()?; 84 | 85 | let resp = get_html_section(&resp, "main").unwrap_or_default(); 86 | let resp = parse_html(&resp); 87 | let resp = resp.trim().to_string(); 88 | Ok(resp) 89 | } 90 | 91 | #[cfg(feature = "html_parsing")] 92 | fn get_html_section(contents: &str, section: &str) -> Option { 93 | let regex = format!("<{}>((.|\n)*?)", section, section); 94 | let regex = Regex::new(®ex).unwrap(); 95 | let html = regex.captures(contents)?.get(1)?.as_str(); 96 | Some(html.to_string()) 97 | } 98 | 99 | #[cfg(feature = "html_parsing")] 100 | pub fn verify(text: &str) -> bool { 101 | text.contains("That's the right answer!") 102 | } 103 | 104 | #[cfg(feature = "html_parsing")] 105 | fn get_title(brief: &str) -> Option { 106 | let regex = Regex::new("

--- Day .*?: (.*?) ---

").unwrap(); 107 | let title = regex.captures(brief)?.get(1)?.as_str(); 108 | Some(title.to_string()) 109 | } 110 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: 3 | push: 4 | tags: 5 | - 'v[0-9]+.[0-9]+.[0-9]+' 6 | 7 | jobs: 8 | release_cli: 9 | needs: release_lib 10 | runs-on: ubuntu-latest 11 | defaults: 12 | run: 13 | working-directory: aocf_cli 14 | steps: 15 | 16 | - name: Checkout 17 | uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Get version 22 | id: get_version 23 | run: echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/v} 24 | 25 | - name: Install dependencies 26 | run: | 27 | sudo apt-get update 28 | sudo apt-get install -y libsqlite3-dev 29 | 30 | - uses: actions-rs/toolchain@v1 31 | with: 32 | profile: minimal 33 | toolchain: stable 34 | components: clippy 35 | override: true 36 | 37 | - name: Build and test tool 38 | run: | 39 | cargo test --verbose 40 | #cargo clippy --verbose --all-features -- -D warnings 41 | cargo build --verbose --release 42 | 43 | - name: Build Debian package for tool 44 | id: build_deb 45 | run: | 46 | cargo install cargo-deb 47 | cargo deb | tee /tmp/deb_out_path # get deb path from output of `cargo deb` 48 | echo "path=$(cat /tmp/deb_out_path)" >> $GITHUB_OUTPUT # provide deb output path as output 49 | 50 | - name: Create Github release 51 | id: make_release 52 | uses: actions/create-release@v1 53 | env: 54 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 55 | with: 56 | tag_name: ${{ github.ref }} 57 | release_name: ${{ github.ref }} 58 | draft: false 59 | prerelease: false 60 | 61 | - name: Upload assets to Github 62 | uses: actions/upload-release-asset@v1.0.1 63 | env: 64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 65 | with: 66 | upload_url: ${{ steps.make_release.outputs.upload_url }} 67 | asset_content_type: application/vnd.debian.binary-package 68 | asset_path: ${{ steps.build_deb.outputs.path }} 69 | asset_name: aocf_cli_${{ steps.get_version.outputs.VERSION }}_amd64.deb 70 | 71 | - name: Publish tool to crates.io 72 | env: 73 | CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} 74 | run: | 75 | cargo login ${CRATES_IO_TOKEN} 76 | cargo publish 77 | 78 | release_lib: 79 | runs-on: ubuntu-latest 80 | steps: 81 | 82 | - name: Checkout 83 | uses: actions/checkout@v2 84 | with: 85 | fetch-depth: 0 86 | 87 | - name: Get version 88 | id: get_version 89 | run: echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/v} 90 | 91 | - name: Install dependencies 92 | run: | 93 | sudo apt-get update 94 | sudo apt-get install -y libsqlite3-dev 95 | 96 | - uses: actions-rs/toolchain@v1 97 | with: 98 | profile: minimal 99 | toolchain: stable 100 | components: clippy 101 | override: true 102 | 103 | - name: Build and test lib 104 | run: | 105 | cargo test --verbose 106 | #cargo clippy --verbose --all-features -- -D warnings 107 | cargo build --verbose --release 108 | 109 | - name: Publish lib to crates.io 110 | env: 111 | CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} 112 | run: | 113 | cargo login ${CRATES_IO_TOKEN} 114 | cargo publish 115 | -------------------------------------------------------------------------------- /aocf_cli/src/cli.rs: -------------------------------------------------------------------------------- 1 | use chrono::{Datelike, Utc}; 2 | use clap::{Args, CommandFactory, Parser}; 3 | use clap_complete::Shell; 4 | 5 | pub fn generate_completion(shell: Shell) { 6 | clap_complete::generate(shell, &mut Aocf::command(), "aocf", &mut std::io::stdout()); 7 | } 8 | 9 | /// Advent of Code Swiss army knife 10 | #[derive(Parser, Debug)] 11 | #[clap(version)] 12 | pub enum Aocf { 13 | /// Switch to a specified year and day 14 | Checkout(AocfTimeDateOpts), 15 | 16 | /// Get input data for the current problem 17 | Input { 18 | /// View in pager 19 | #[clap(short, long = "pager")] 20 | view: bool, 21 | 22 | /// Don't use cache 23 | #[clap(short, long)] 24 | force: bool, 25 | 26 | /// Show input data stats 27 | #[clap(short, long, conflicts_with = "view")] 28 | info: bool, 29 | }, 30 | 31 | /// Get instructions for the current problem 32 | Brief { 33 | /// View pretty 34 | #[clap(short, long, conflicts_with = "view")] 35 | pretty: bool, 36 | 37 | /// View in pager 38 | #[clap(short, long = "pager", conflicts_with = "pretty")] 39 | view: bool, 40 | 41 | /// View in web browser 42 | #[clap(short, long, conflicts_with_all = &["pretty", "view"])] 43 | web: bool, 44 | 45 | /// View current day and year 46 | #[clap(short, long, conflicts_with = "day")] 47 | now: bool, 48 | 49 | /// Problem day to view 50 | #[clap(short, long, conflicts_with = "now")] 51 | day: Option, 52 | 53 | /// Don't use cache 54 | #[clap(short, long)] 55 | force: bool, 56 | }, 57 | 58 | /// Submit an answer for the current problem and level 59 | Submit { 60 | /// Your answer 61 | answer: String, 62 | }, 63 | 64 | /// Fetch brief and input data, if available 65 | Fetch { 66 | /// Don't use cache 67 | #[clap(short, long)] 68 | force: bool, 69 | 70 | /// Use current day and year 71 | #[clap(short, long, conflicts_with = "day")] 72 | now: bool, 73 | 74 | /// Problem day to use 75 | #[clap(short, long, conflicts_with = "now")] 76 | day: Option, 77 | }, 78 | 79 | /// Get current status 80 | Status, 81 | 82 | /// Get summary of challenges and stars 83 | Summary { 84 | /// Specify the challenge year to view 85 | #[clap(short, long)] 86 | year: Option, 87 | }, 88 | 89 | /// Initialise an aocf repository 90 | Init, 91 | 92 | /// Set authentication token text 93 | SetCookie { 94 | /// Contents of authentication token to store 95 | token: String, 96 | }, 97 | 98 | /// Get authentication token from firefox cookie store 99 | GetCookie, 100 | 101 | /// Generate shell completion script 102 | Completion { 103 | /// Shell type 104 | #[clap(arg_enum)] 105 | shell: Shell, 106 | }, 107 | } 108 | 109 | #[derive(Args, Debug)] 110 | pub struct AocfTimeDateOpts { 111 | /// Check out current day and year 112 | #[clap(short, long, conflicts_with_all = &["problem-day", "problem-year", "day", "year"])] 113 | now: bool, 114 | 115 | /// Problem day 116 | #[clap(short, long)] 117 | day: Option, 118 | 119 | /// Problem year 120 | #[clap(short, long)] 121 | year: Option, 122 | 123 | /// Problem day 124 | #[clap(conflicts_with_all = &["now", "day"], required_unless_present_any = &["now", "day"])] 125 | problem_day: Option, 126 | 127 | /// Problem year 128 | #[clap(conflicts_with_all = &["now", "year"])] 129 | problem_year: Option, 130 | } 131 | 132 | impl AocfTimeDateOpts { 133 | pub fn get_day_year(&self) -> (Option, Option) { 134 | match self { 135 | Self { now: true, .. } => { 136 | let now = Utc::now(); 137 | (Some(now.day()), Some(now.year())) 138 | }, 139 | Self { day: Some(d), year, .. } => { 140 | (Some(*d), *year) 141 | }, 142 | Self { problem_day: Some(d), problem_year, .. } => { 143 | (Some(*d), *problem_year) 144 | }, 145 | _ => (None, None), 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /aocf_cli/src/bin/aocf.rs: -------------------------------------------------------------------------------- 1 | use aocf::{ 2 | Aoc, 3 | cookie::get_session_cookie, 4 | find_root, 5 | Level, 6 | }; 7 | use aocf_cli::{ 8 | cli::{Aocf, AocfTimeDateOpts, generate_completion}, 9 | conf::Conf, 10 | pretty::make_pretty, 11 | }; 12 | use dirs::home_dir; 13 | use std::env; 14 | use std::fs; 15 | use std::io::Write; 16 | use std::process::{self, Stdio}; 17 | use tempfile::tempdir; 18 | use glob::glob; 19 | use failure::{Error, bail, format_err}; 20 | use regex::Regex; 21 | use clap::Parser; 22 | use chrono::{Utc, Datelike}; 23 | use webbrowser; 24 | 25 | fn main() { 26 | let opt = Aocf::parse(); 27 | 28 | run(&opt).unwrap_or_else(|err| { 29 | eprintln!("error: {}", err); 30 | process::exit(1); 31 | }); 32 | } 33 | 34 | fn find_config() -> Result { 35 | let conf_path = find_root()?.join(".aocf/config"); 36 | Conf::load(&conf_path) 37 | } 38 | 39 | fn write_conf(conf: &Conf) -> Result<(), Error> { 40 | let conf_path = find_root()?.join(".aocf/config"); 41 | conf.write(&conf_path) 42 | } 43 | 44 | fn run(args: &Aocf) -> Result<(), Error> { 45 | match args { 46 | Aocf::Init => return init(), 47 | Aocf::SetCookie { token } => return set_cookie(token), 48 | Aocf::GetCookie => return get_cookie(), 49 | Aocf::Completion { shell } => return { 50 | generate_completion(*shell); 51 | Ok(()) 52 | }, 53 | _ => (), 54 | }; 55 | 56 | let mut conf = find_config() 57 | .map_err(|e| format_err!("loading config: {}", e))?; 58 | 59 | let conf_hash = conf.calc_hash(); 60 | 61 | // Check that the cookie is in place 62 | let cookie_path = find_root()?.join(".aocf/cookie"); 63 | if !cookie_path.exists() { 64 | bail!("cookie not found, please run set-cookie or get-cookie"); 65 | } 66 | 67 | let mut aoc = Aoc::new() 68 | .parse_cli(false) 69 | .year(Some(conf.year)) 70 | .day(Some(conf.day)) 71 | .init()?; 72 | 73 | match args { 74 | Aocf::Fetch { force, now, day } => { 75 | aoc = if *now { 76 | let now = Utc::now(); 77 | Aoc::new() 78 | .parse_cli(false) 79 | .year(Some(now.year())) 80 | .day(Some(now.day())) 81 | .init()? 82 | } else if let Some(d) = day { 83 | Aoc::new() 84 | .parse_cli(false) 85 | .year(aoc.year) 86 | .day(Some(*d)) 87 | .init()? 88 | } else { 89 | aoc 90 | }; 91 | 92 | let _ = aoc.get_brief(*force)?; 93 | let _ = aoc.get_input(*force)?; 94 | aoc.write()?; 95 | }, 96 | Aocf::Brief { pretty, view, force, now, day, web } => { 97 | aoc = if *now { 98 | let now = Utc::now(); 99 | Aoc::new() 100 | .parse_cli(false) 101 | .year(Some(now.year())) 102 | .day(Some(now.day())) 103 | .init()? 104 | } else if let Some(d) = day { 105 | Aoc::new() 106 | .parse_cli(false) 107 | .year(aoc.year) 108 | .day(Some(*d)) 109 | .init()? 110 | } else { 111 | aoc 112 | }; 113 | 114 | if *web { 115 | if let (Some(d), Some(y)) = (aoc.day, aoc.year) { 116 | let url = format!("https://adventofcode.com/{}/day/{}", y, d); 117 | match webbrowser::open(&url) { 118 | Ok(_) => eprintln!("opened brief for day {}, year {} in web browser", d, y), 119 | Err(e) => bail!(e), 120 | }; 121 | } 122 | } else { 123 | let brief = aoc.get_brief(*force)?; 124 | aoc.write()?; 125 | display(*pretty, *view, &conf, &brief)? 126 | } 127 | }, 128 | Aocf::Input { view, force, info } => { 129 | let input = aoc.get_input(*force)?; 130 | aoc.write()?; 131 | if *info { 132 | strinfo(&input)? 133 | } else { 134 | display(false, *view, &conf, &input)? 135 | } 136 | }, 137 | Aocf::Submit { answer } => { 138 | println!("{}", aoc.submit(answer)?); 139 | aoc.write()?; 140 | }, 141 | Aocf::Status { .. } => status(&aoc)?, 142 | Aocf::Summary { year } => summary(*year, conf.year)?, 143 | Aocf::Checkout ( args ) => checkout(&mut conf, conf_hash, args)?, 144 | Aocf::Init | Aocf::SetCookie { .. } | Aocf::GetCookie | Aocf::Completion { .. } => (), 145 | }; 146 | 147 | // Update configuration if changed since start 148 | if conf.calc_hash() != conf_hash { 149 | write_conf(&conf)?; 150 | } 151 | 152 | Ok(()) 153 | } 154 | 155 | fn strinfo(text: &str) -> Result<(), Error> { 156 | println!("{} bytes, {} lines", text.len(), text.lines().count()); 157 | Ok(()) 158 | } 159 | 160 | fn display(pretty: bool, view: bool, conf: &Conf, text: &str) -> Result<(), Error> { 161 | if pretty { 162 | // Cludgily post-process markdown 163 | let re = Regex::new(r"`\*(?P.+?)\*`").unwrap(); 164 | let display_text: String = text.lines() 165 | .map(|l| format!("{}\n", l)) 166 | .map(|l| re.replace_all(&l, "*`$content`*").to_string()) 167 | .collect::() 168 | .replace(": \\*\\*", ": **`**`**") 169 | .replace(": \\*", ": **`*`**") 170 | .replace("\\---", "---"); 171 | make_pretty(&display_text)?; 172 | } else if view { 173 | pager(conf, text)?; 174 | } else { 175 | print!("{}", text); 176 | } 177 | Ok(()) 178 | } 179 | 180 | fn pager(conf: &Conf, text: &str) -> Result<(), Error> { 181 | let mut process = process::Command::new(&conf.pager) 182 | .stdin(Stdio::piped()) 183 | .spawn()?; 184 | 185 | let mut stdin = process.stdin.take().unwrap(); 186 | stdin.write_all(text.as_bytes())?; 187 | stdin.flush()?; 188 | drop(stdin); 189 | process.wait()?; 190 | Ok(()) 191 | } 192 | 193 | fn status(aoc: &Aoc) -> Result<(), Error> { 194 | if let (Some(d), Some(y)) = (aoc.day, aoc.year) { 195 | eprintln!("{:<6} {}", "year:", y); 196 | eprintln!("day: {}", d); 197 | } else { 198 | bail!("day or year not set") 199 | } 200 | eprintln!("level: {}", aoc.level); 201 | if let Some(t) = &aoc.title { 202 | eprintln!("title: {}", t); 203 | }; 204 | if !aoc.solution.is_empty() { 205 | eprintln!("solutions:"); 206 | 207 | if let Some(s) = aoc.solution.get(&Level::First) { 208 | eprintln!(" 1) {} ", s); 209 | } 210 | if let Some(s) = aoc.solution.get(&Level::Second) { 211 | eprintln!(" 2) {} ", s); 212 | } 213 | } 214 | if let Some(s) = aoc.stars { 215 | eprint!("stars: "); 216 | for _ in 0..s { eprint!("*"); }; 217 | eprintln!(); 218 | }; 219 | Ok(()) 220 | } 221 | 222 | fn summary(arg_year: Option, conf_year: i32) -> Result<(), Error> { 223 | let year = arg_year.unwrap_or(conf_year); 224 | 225 | let mut configs: Vec<_> = fs::read_dir(find_root()?.join(".aocf/cache"))? 226 | .map(|r| r.map(|e| e.path())) 227 | .flatten() 228 | .map(Aoc::load_json_from) 229 | .flatten() 230 | .filter(|a| a.year == Some(year)) 231 | .collect(); 232 | 233 | configs.sort_by(|a, b| a.day.cmp(&b.day)); 234 | 235 | configs 236 | .iter() 237 | .for_each(|p| { 238 | if let (Some(y), Some(d), Some(t), Some(s)) = (p.year, p.day, &p.title, p.stars) { 239 | let s: String = "*".repeat(s.into()); 240 | println!("{} {:2} {:2} {}", y, d, s, t); 241 | } 242 | }); 243 | 244 | Ok(()) 245 | } 246 | 247 | fn init() -> Result<(), Error> { 248 | let conf_path = env::current_dir()?.join(".aocf"); 249 | fs::create_dir_all(&conf_path)?; 250 | 251 | let config_path = conf_path.join("config"); 252 | if config_path.exists() { 253 | bail!("configuration already exists at {}", config_path.display()); 254 | }; 255 | 256 | let conf = Conf::default(); 257 | conf.write(&config_path)?; 258 | 259 | eprintln!("initialised config at {}", config_path.display()); 260 | 261 | Ok(()) 262 | } 263 | 264 | fn checkout(conf: &mut Conf, conf_hash: u64, args: &AocfTimeDateOpts) -> Result<(), Error> { 265 | let (day, year) = args.get_day_year(); 266 | 267 | if let Some(d) = day { 268 | conf.day = d; 269 | } else { 270 | bail!("no day provided"); 271 | } 272 | 273 | if let Some(y) = year { 274 | conf.year = y; 275 | } 276 | 277 | if conf.calc_hash() != conf_hash { 278 | eprintln!("switched to year {}, day {}", conf.year, conf.day); 279 | }; 280 | 281 | Ok(()) 282 | } 283 | 284 | fn set_cookie(cookie: &str) -> Result<(), Error> { 285 | let cookie_path = find_root()?.join(".aocf/cookie"); 286 | let mut file = fs::File::create(cookie_path)?; 287 | 288 | // write out a .gitignore to avoid committing the cookie data (which 289 | // would be very insecure!) 290 | let gitignore_path = find_root()?.join(".aocf/.gitignore"); 291 | if !gitignore_path.exists() { 292 | let mut gitignore = fs::File::create(gitignore_path)?; 293 | gitignore.write_all(b"cookie\n")?; 294 | } 295 | 296 | Ok(file.write_all(cookie.as_bytes())?) 297 | } 298 | 299 | fn get_cookie() -> Result<(), Error> { 300 | let cookie_store_dir = match home_dir() { 301 | None => bail!("can't get home directory"), 302 | Some(d) => { 303 | if let Some(p) = d.join(".mozilla/firefox/*.default/cookies.sqlite").to_str() { 304 | match glob(p) { 305 | Ok(mut path) => path.next(), 306 | Err(e) => bail!("{:?}", e), 307 | } 308 | } else { 309 | bail!("can't get cookie store path"); 310 | } 311 | } 312 | }; 313 | 314 | // copy the cookie store to a temporary location, if firefox is open, the 315 | // store will be locked 316 | let tmp_dir = tempdir()?; 317 | let tmp_path = tmp_dir.path().join("cookies.sqlite"); 318 | if let Some(Ok(path)) = cookie_store_dir { 319 | eprintln!("found cookie store: {}", path.display()); 320 | fs::copy(&path, &tmp_path)?; 321 | } else { 322 | bail!("couldn't get cookie store path"); 323 | } 324 | 325 | let cookie_value = get_session_cookie(&tmp_path)?; 326 | set_cookie(&cookie_value) 327 | } 328 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "sqlite")] 2 | #[macro_use] extern crate diesel; 3 | #[macro_use] extern crate serde_derive; 4 | 5 | use std::collections::{HashMap, BTreeMap}; 6 | use std::fmt; 7 | use std::fs::{File, read_to_string, create_dir_all}; 8 | use std::io::{self, Write, BufRead}; 9 | use std::path::{Path, PathBuf}; 10 | use std::env::current_dir; 11 | use serde::{Serialize, Serializer}; 12 | use failure::{Error, bail}; 13 | 14 | mod http; 15 | #[cfg(feature = "sqlite")] 16 | pub mod cookie; 17 | mod cli; 18 | 19 | use cli::AocOpts; 20 | use clap::Parser; 21 | use atty::{is, Stream}; 22 | 23 | #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Serialize, Deserialize)] 24 | #[serde(rename_all = "lowercase")] 25 | pub enum Level { 26 | First, 27 | Second, 28 | } 29 | 30 | impl Default for Level { 31 | fn default() -> Self { 32 | Self::First 33 | } 34 | } 35 | 36 | impl fmt::Display for Level { 37 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 38 | let s = match self { 39 | Level::First => "first", 40 | Level::Second => "second", 41 | }; 42 | write!(f, "{}", s) 43 | } 44 | } 45 | 46 | /// A cache entry for a single day, containing all data related to that day's problem 47 | #[derive(Debug, Default, Clone, Serialize, Deserialize)] 48 | pub struct Aoc { 49 | pub year: Option, 50 | pub day: Option, 51 | pub level: Level, 52 | pub title: Option, 53 | pub stars: Option, 54 | pub solution: HashMap, 55 | 56 | input: Option, 57 | #[serde(serialize_with = "ordered_map")] 58 | brief: HashMap, 59 | #[serde(serialize_with = "ordered_map")] 60 | 61 | #[serde(skip)] 62 | cookie: String, 63 | #[serde(skip)] 64 | cache_path: Option, 65 | #[serde(skip)] 66 | cookie_path: Option, 67 | /// Whether to parse CLI arguments locally 68 | #[serde(skip)] 69 | parse_cli: bool, 70 | /// Input file provided on CLI 71 | #[serde(skip)] 72 | input_file: Option, 73 | /// Whether the process is piped 74 | #[serde(skip)] 75 | stream: bool, 76 | } 77 | 78 | impl Aoc { 79 | pub fn new() -> Self { 80 | Aoc { parse_cli: true, ..Default::default() } 81 | } 82 | 83 | /// Set the year 84 | pub fn year(mut self, year: Option) -> Self { 85 | self.year = year; 86 | self 87 | } 88 | 89 | /// Set the day 90 | pub fn day(mut self, day: Option) -> Self { 91 | self.day = day; 92 | self 93 | } 94 | 95 | /// Set cookie string 96 | pub fn cookie(mut self, cookie: &str) -> Self { 97 | self.cookie = cookie.to_string(); 98 | self 99 | } 100 | 101 | /// Set cookie file 102 | pub fn cookie_file(mut self, path: impl AsRef) -> Self { 103 | self.cookie_path = Some(path.as_ref().to_path_buf()); 104 | self 105 | } 106 | 107 | /// Set the cache path 108 | // pub fn cache

(&mut self, path: P) -> &mut Self 109 | // where P: AsRef + std::clone::Clone, 110 | // { 111 | pub fn cache

(mut self, path: Option<&Path>) -> Self { 112 | self.cache_path = path.as_ref().map(PathBuf::from); 113 | self 114 | } 115 | 116 | /// Enable or disable CLI argument parsing 117 | /// 118 | /// If enabled, the binary's arguments will be parsed, allowing for 119 | /// example, to choose a file to read in as alternative input data, 120 | /// rather than using the input data fetched from Advent of Code. 121 | pub fn parse_cli(mut self, status: bool) -> Self { 122 | self.parse_cli = status; 123 | self 124 | } 125 | 126 | /// Initialise (finish building) 127 | pub fn init(mut self) -> Result { 128 | // Attempt to load cookie data 129 | if self.cookie.is_empty() { 130 | if let Some(p) = &self.cookie_path { 131 | self.cookie = read_to_string(p)?.trim().to_string() 132 | } else if let Ok(p) = self.get_default_cookie_path() { 133 | self.cookie = read_to_string(p)?.trim().to_string() 134 | }; 135 | } 136 | 137 | // Process CLI args 138 | if self.parse_cli { 139 | let opt = AocOpts::parse(); 140 | self.input_file = opt.input; 141 | } 142 | 143 | // Process piped status of the process 144 | self.stream = is(Stream::Stdin); 145 | 146 | if let Ok(mut aoc) = self.load() { 147 | // re-instate fields which will need to be overriden after successful load 148 | aoc.cookie = self.cookie; 149 | aoc.input_file = self.input_file; 150 | aoc.stream = self.stream; 151 | Ok(aoc) 152 | } else { 153 | Ok(self) 154 | } 155 | } 156 | 157 | /// Get the problem brief as HTML and sanitise it to markdown 158 | #[cfg(feature = "html_parsing")] 159 | pub fn get_brief(&mut self, force: bool) -> Result { 160 | if self.brief.get(&self.level).is_none() || force { 161 | let brief = http::get_brief(self)?; 162 | self.title = Some(brief.0); 163 | self.brief.insert(self.level, brief.1); 164 | self.write()?; 165 | }; 166 | Ok(self.brief.get(&self.level).unwrap().to_string()) 167 | } 168 | 169 | /// Get the input data 170 | pub fn get_input(&mut self, force: bool) -> Result { 171 | // Input file provided on CLI, read it 172 | if let Some(file) = &self.input_file { 173 | return Ok(read_to_string(file)?.trim().to_string()) 174 | } 175 | 176 | // We are piped, read the piped data 177 | if !self.stream { 178 | let stdin = io::stdin(); 179 | 180 | let data = stdin.lock().lines() 181 | .flatten() 182 | .fold(String::new(), |mut acc, line| { 183 | acc.push_str(&format!("{}\n", line)); 184 | acc 185 | }); 186 | 187 | return Ok(data); 188 | } 189 | 190 | // Get input data from adventofcode.com 191 | if self.input.is_none() || force { 192 | let input = http::get_input(self)?; 193 | self.input = Some(input); 194 | self.write()?; 195 | } 196 | 197 | Ok(self.input.clone().unwrap()) 198 | } 199 | 200 | /// Submit the solution 201 | #[cfg(feature = "html_parsing")] 202 | pub fn submit(&mut self, solution: &str) -> Result { 203 | let resp = http::submit(self, solution)?; 204 | if http::verify(&resp) { 205 | self.solution.insert(self.level, solution.to_string()); 206 | self.get_brief(true).ok(); // Update brief (force) to update stars 207 | self.add_star(); 208 | self.advance().unwrap_or(()); 209 | self.write()?; 210 | } 211 | Ok(resp) 212 | } 213 | 214 | #[cfg(feature = "html_parsing")] 215 | fn add_star(&mut self) { 216 | if let Some(ref stars) = self.stars { 217 | self.stars = Some(stars + 1); 218 | } else { 219 | self.stars = Some(1); 220 | }; 221 | } 222 | 223 | /// get a JSON representation for the AoC problem 224 | pub fn to_json(&self) -> Result { 225 | Ok(serde_json::to_string_pretty(self)?) 226 | } 227 | 228 | /// get an AoC problem from JSON representation 229 | pub fn from_json(json: &str) -> Result { 230 | Ok(serde_json::from_str(json)?) 231 | } 232 | 233 | /// Save problem to path as JSON 234 | pub fn write_json_to(&self, path: impl AsRef) -> Result<(), Error> { 235 | ensure_parent_dir(path.as_ref())?; 236 | let mut file = File::create(path)?; 237 | file.write_all(self.to_json()?.as_bytes())?; 238 | Ok(()) 239 | } 240 | 241 | /// Load the problem from JSON 242 | pub fn load_json_from(path: impl AsRef) -> Result { 243 | let json = read_to_string(path)?; 244 | Self::from_json(&json) 245 | } 246 | 247 | /// Write JSON cache 248 | pub fn write(&self) -> Result<(), Error> { 249 | if let Some(ref p) = self.cache_path { 250 | self.write_json_to(p) 251 | } else { 252 | self.write_json_to(self.get_default_cache_path()?) 253 | } 254 | } 255 | 256 | pub fn advance(&mut self) -> Result<(), Error> { 257 | match self.level { 258 | Level::First => { self.level = Level::Second; Ok(()) }, 259 | Level::Second => bail!("already on part 2"), 260 | } 261 | } 262 | 263 | fn load(&self) -> Result { 264 | if let Some(ref p) = self.cache_path { 265 | Self::load_json_from(p) 266 | } else { 267 | Self::load_json_from(self.get_default_cache_path()?) 268 | } 269 | } 270 | 271 | fn get_default_cookie_path(&self) -> Result { 272 | let p = PathBuf::from("./.aocf/cookie"); 273 | if let Ok(r) = find_root() { 274 | Ok(r.join(p)) 275 | } else { 276 | Ok(p) 277 | } 278 | } 279 | 280 | fn get_default_cache_path(&self) -> Result { 281 | if let (Some(y), Some(d)) = (self.year, self.day) { 282 | let p = PathBuf::from(&format!("./.aocf/cache/aoc{}_{:02}.json", y, d)); 283 | if let Ok(r) = find_root() { 284 | Ok(r.join(p)) 285 | } else { 286 | Ok(p) 287 | } 288 | } else { 289 | bail!("day or year not set"); 290 | } 291 | } 292 | 293 | /// Get time until release 294 | pub fn get_time_until_release() { 295 | 296 | } 297 | } 298 | 299 | /// Get an ordered hashmap representation when serialising 300 | fn ordered_map(value: &HashMap, serializer: S) -> Result 301 | where 302 | S: Serializer, 303 | { 304 | let ordered: BTreeMap<_, _> = value.iter().collect(); 305 | ordered.serialize(serializer) 306 | } 307 | 308 | fn ensure_parent_dir(file: impl AsRef) -> Result<(), Error> { 309 | let without_path = file.as_ref().components().count() == 1; 310 | match file.as_ref().parent() { 311 | Some(dir) if !without_path => create_dir_all(dir)?, 312 | _ => (), 313 | }; 314 | Ok(()) 315 | } 316 | 317 | /// Find configuration directory in current directory or its ancestors 318 | pub fn find_root() -> Result { 319 | let cwd = current_dir()?; 320 | 321 | let conf_dir = cwd.ancestors() 322 | .find(|dir| dir.join(".aocf").is_dir()) 323 | .filter(|dir| dir.join(".aocf/config").is_file()); 324 | 325 | match conf_dir { 326 | Some(dir) => Ok(dir.to_path_buf()), 327 | None => bail!("no configuration found, maybe you need to run `aocf init`"), 328 | } 329 | } 330 | 331 | #[cfg(test)] 332 | mod tests { 333 | use super::*; 334 | use tempfile::tempdir; 335 | use std::env; 336 | use std::fs; 337 | 338 | #[test] 339 | fn test_find_root() { 340 | let tmp = tempdir().unwrap(); 341 | let tmp_path = tmp.path(); 342 | let tmp_sub = tmp_path.join("im/in/a-subdir"); 343 | fs::create_dir_all(&tmp_sub).unwrap(); 344 | 345 | env::set_current_dir(tmp_path).unwrap(); 346 | assert!(find_root().is_err()); 347 | fs::create_dir(tmp_path.join(".aocf")).unwrap(); 348 | assert!(find_root().is_err()); 349 | File::create(tmp_path.join(".aocf/config")).unwrap(); 350 | assert!(find_root().is_ok()); 351 | env::set_current_dir(tmp_sub).unwrap(); 352 | if cfg!(linux) || cfg!(windows) { 353 | /* Very strange result on macos... 354 | * 355 | * ---- tests::test_find_root stdout ---- 356 | * thread 'tests::test_find_root' panicked at 'assertion failed: `(left == right)` 357 | * left: `"/private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/.tmpUwUaSn"`, 358 | * right: `"/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/.tmpUwUaSn"`', src/lib.rs:292:13 359 | * note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace 360 | * 361 | let left: PathBuf = find_root().unwrap().components().skip(5).collect(); 362 | let right: PathBuf = tmp_path.components().skip(4).collect(); 363 | assert_eq!(left, right); 364 | */ 365 | assert_eq!(find_root().unwrap(), tmp_path); 366 | } 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /aocf_cli/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.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 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.2" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" 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.4" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" 49 | dependencies = [ 50 | "anstyle", 51 | "anstyle-parse", 52 | "anstyle-query", 53 | "anstyle-wincon", 54 | "colorchoice", 55 | "utf8parse", 56 | ] 57 | 58 | [[package]] 59 | name = "anstyle" 60 | version = "1.0.4" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" 63 | 64 | [[package]] 65 | name = "anstyle-parse" 66 | version = "0.2.3" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" 69 | dependencies = [ 70 | "utf8parse", 71 | ] 72 | 73 | [[package]] 74 | name = "anstyle-query" 75 | version = "1.0.1" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" 78 | dependencies = [ 79 | "windows-sys 0.52.0", 80 | ] 81 | 82 | [[package]] 83 | name = "anstyle-wincon" 84 | version = "3.0.2" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" 87 | dependencies = [ 88 | "anstyle", 89 | "windows-sys 0.52.0", 90 | ] 91 | 92 | [[package]] 93 | name = "aocf" 94 | version = "0.1.21" 95 | dependencies = [ 96 | "atty", 97 | "clap 4.4.11", 98 | "diesel", 99 | "failure", 100 | "html2md", 101 | "libsqlite3-sys", 102 | "regex", 103 | "serde", 104 | "serde_derive", 105 | "serde_json", 106 | "tempfile", 107 | "ureq", 108 | ] 109 | 110 | [[package]] 111 | name = "aocf_cli" 112 | version = "0.1.21" 113 | dependencies = [ 114 | "aocf", 115 | "chrono", 116 | "clap 3.2.25", 117 | "clap_complete", 118 | "crossterm", 119 | "dirs", 120 | "failure", 121 | "glob", 122 | "regex", 123 | "serde", 124 | "serde_derive", 125 | "tempfile", 126 | "termimad", 127 | "toml", 128 | "webbrowser", 129 | ] 130 | 131 | [[package]] 132 | name = "atty" 133 | version = "0.2.14" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 136 | dependencies = [ 137 | "hermit-abi", 138 | "libc", 139 | "winapi", 140 | ] 141 | 142 | [[package]] 143 | name = "autocfg" 144 | version = "1.1.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 147 | 148 | [[package]] 149 | name = "backtrace" 150 | version = "0.3.69" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" 153 | dependencies = [ 154 | "addr2line", 155 | "cc", 156 | "cfg-if 1.0.0", 157 | "libc", 158 | "miniz_oxide", 159 | "object", 160 | "rustc-demangle", 161 | ] 162 | 163 | [[package]] 164 | name = "base64" 165 | version = "0.21.5" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" 168 | 169 | [[package]] 170 | name = "bitflags" 171 | version = "1.3.2" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 174 | 175 | [[package]] 176 | name = "bitflags" 177 | version = "2.4.1" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" 180 | 181 | [[package]] 182 | name = "bumpalo" 183 | version = "3.14.0" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" 186 | 187 | [[package]] 188 | name = "byteorder" 189 | version = "1.5.0" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 192 | 193 | [[package]] 194 | name = "bytes" 195 | version = "1.5.0" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" 198 | 199 | [[package]] 200 | name = "cc" 201 | version = "1.0.83" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 204 | dependencies = [ 205 | "libc", 206 | ] 207 | 208 | [[package]] 209 | name = "cesu8" 210 | version = "1.1.0" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" 213 | 214 | [[package]] 215 | name = "cfg-if" 216 | version = "0.1.10" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 219 | 220 | [[package]] 221 | name = "cfg-if" 222 | version = "1.0.0" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 225 | 226 | [[package]] 227 | name = "chrono" 228 | version = "0.4.31" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" 231 | dependencies = [ 232 | "android-tzdata", 233 | "iana-time-zone", 234 | "js-sys", 235 | "num-traits", 236 | "wasm-bindgen", 237 | "windows-targets 0.48.5", 238 | ] 239 | 240 | [[package]] 241 | name = "clap" 242 | version = "3.2.25" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" 245 | dependencies = [ 246 | "atty", 247 | "bitflags 1.3.2", 248 | "clap_derive 3.2.25", 249 | "clap_lex 0.2.4", 250 | "indexmap", 251 | "once_cell", 252 | "strsim", 253 | "termcolor", 254 | "textwrap", 255 | ] 256 | 257 | [[package]] 258 | name = "clap" 259 | version = "4.4.11" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" 262 | dependencies = [ 263 | "clap_builder", 264 | "clap_derive 4.4.7", 265 | ] 266 | 267 | [[package]] 268 | name = "clap_builder" 269 | version = "4.4.11" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" 272 | dependencies = [ 273 | "anstream", 274 | "anstyle", 275 | "clap_lex 0.6.0", 276 | "strsim", 277 | ] 278 | 279 | [[package]] 280 | name = "clap_complete" 281 | version = "3.2.5" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8" 284 | dependencies = [ 285 | "clap 3.2.25", 286 | ] 287 | 288 | [[package]] 289 | name = "clap_derive" 290 | version = "3.2.25" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" 293 | dependencies = [ 294 | "heck", 295 | "proc-macro-error", 296 | "proc-macro2", 297 | "quote", 298 | "syn 1.0.109", 299 | ] 300 | 301 | [[package]] 302 | name = "clap_derive" 303 | version = "4.4.7" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" 306 | dependencies = [ 307 | "heck", 308 | "proc-macro2", 309 | "quote", 310 | "syn 2.0.39", 311 | ] 312 | 313 | [[package]] 314 | name = "clap_lex" 315 | version = "0.2.4" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 318 | dependencies = [ 319 | "os_str_bytes", 320 | ] 321 | 322 | [[package]] 323 | name = "clap_lex" 324 | version = "0.6.0" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" 327 | 328 | [[package]] 329 | name = "cloudabi" 330 | version = "0.0.3" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 333 | dependencies = [ 334 | "bitflags 1.3.2", 335 | ] 336 | 337 | [[package]] 338 | name = "colorchoice" 339 | version = "1.0.0" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 342 | 343 | [[package]] 344 | name = "combine" 345 | version = "4.6.6" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" 348 | dependencies = [ 349 | "bytes", 350 | "memchr", 351 | ] 352 | 353 | [[package]] 354 | name = "core-foundation-sys" 355 | version = "0.8.6" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 358 | 359 | [[package]] 360 | name = "crc32fast" 361 | version = "1.3.2" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 364 | dependencies = [ 365 | "cfg-if 1.0.0", 366 | ] 367 | 368 | [[package]] 369 | name = "crossbeam" 370 | version = "0.8.2" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" 373 | dependencies = [ 374 | "cfg-if 1.0.0", 375 | "crossbeam-channel", 376 | "crossbeam-deque", 377 | "crossbeam-epoch", 378 | "crossbeam-queue", 379 | "crossbeam-utils", 380 | ] 381 | 382 | [[package]] 383 | name = "crossbeam-channel" 384 | version = "0.5.8" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" 387 | dependencies = [ 388 | "cfg-if 1.0.0", 389 | "crossbeam-utils", 390 | ] 391 | 392 | [[package]] 393 | name = "crossbeam-deque" 394 | version = "0.8.3" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" 397 | dependencies = [ 398 | "cfg-if 1.0.0", 399 | "crossbeam-epoch", 400 | "crossbeam-utils", 401 | ] 402 | 403 | [[package]] 404 | name = "crossbeam-epoch" 405 | version = "0.9.15" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" 408 | dependencies = [ 409 | "autocfg", 410 | "cfg-if 1.0.0", 411 | "crossbeam-utils", 412 | "memoffset", 413 | "scopeguard", 414 | ] 415 | 416 | [[package]] 417 | name = "crossbeam-queue" 418 | version = "0.3.8" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" 421 | dependencies = [ 422 | "cfg-if 1.0.0", 423 | "crossbeam-utils", 424 | ] 425 | 426 | [[package]] 427 | name = "crossbeam-utils" 428 | version = "0.8.16" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" 431 | dependencies = [ 432 | "cfg-if 1.0.0", 433 | ] 434 | 435 | [[package]] 436 | name = "crossterm" 437 | version = "0.17.7" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "6f4919d60f26ae233e14233cc39746c8c8bb8cd7b05840ace83604917b51b6c7" 440 | dependencies = [ 441 | "bitflags 1.3.2", 442 | "crossterm_winapi", 443 | "lazy_static", 444 | "libc", 445 | "mio", 446 | "parking_lot 0.10.2", 447 | "signal-hook", 448 | "winapi", 449 | ] 450 | 451 | [[package]] 452 | name = "crossterm_winapi" 453 | version = "0.6.2" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "c2265c3f8e080075d9b6417aa72293fc71662f34b4af2612d8d1b074d29510db" 456 | dependencies = [ 457 | "winapi", 458 | ] 459 | 460 | [[package]] 461 | name = "diesel" 462 | version = "1.4.8" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d" 465 | dependencies = [ 466 | "byteorder", 467 | "diesel_derives", 468 | "libsqlite3-sys", 469 | ] 470 | 471 | [[package]] 472 | name = "diesel_derives" 473 | version = "1.4.1" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" 476 | dependencies = [ 477 | "proc-macro2", 478 | "quote", 479 | "syn 1.0.109", 480 | ] 481 | 482 | [[package]] 483 | name = "dirs" 484 | version = "3.0.2" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" 487 | dependencies = [ 488 | "dirs-sys", 489 | ] 490 | 491 | [[package]] 492 | name = "dirs-sys" 493 | version = "0.3.7" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 496 | dependencies = [ 497 | "libc", 498 | "redox_users", 499 | "winapi", 500 | ] 501 | 502 | [[package]] 503 | name = "errno" 504 | version = "0.3.8" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 507 | dependencies = [ 508 | "libc", 509 | "windows-sys 0.52.0", 510 | ] 511 | 512 | [[package]] 513 | name = "failure" 514 | version = "0.1.8" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 517 | dependencies = [ 518 | "backtrace", 519 | "failure_derive", 520 | ] 521 | 522 | [[package]] 523 | name = "failure_derive" 524 | version = "0.1.8" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 527 | dependencies = [ 528 | "proc-macro2", 529 | "quote", 530 | "syn 1.0.109", 531 | "synstructure", 532 | ] 533 | 534 | [[package]] 535 | name = "fastrand" 536 | version = "2.0.1" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" 539 | 540 | [[package]] 541 | name = "flate2" 542 | version = "1.0.28" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" 545 | dependencies = [ 546 | "crc32fast", 547 | "miniz_oxide", 548 | ] 549 | 550 | [[package]] 551 | name = "form_urlencoded" 552 | version = "1.2.1" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 555 | dependencies = [ 556 | "percent-encoding", 557 | ] 558 | 559 | [[package]] 560 | name = "futf" 561 | version = "0.1.5" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" 564 | dependencies = [ 565 | "mac", 566 | "new_debug_unreachable", 567 | ] 568 | 569 | [[package]] 570 | name = "getrandom" 571 | version = "0.2.11" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" 574 | dependencies = [ 575 | "cfg-if 1.0.0", 576 | "libc", 577 | "wasi", 578 | ] 579 | 580 | [[package]] 581 | name = "gimli" 582 | version = "0.28.1" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 585 | 586 | [[package]] 587 | name = "glob" 588 | version = "0.3.1" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 591 | 592 | [[package]] 593 | name = "hashbrown" 594 | version = "0.12.3" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 597 | 598 | [[package]] 599 | name = "heck" 600 | version = "0.4.1" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 603 | 604 | [[package]] 605 | name = "hermit-abi" 606 | version = "0.1.19" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 609 | dependencies = [ 610 | "libc", 611 | ] 612 | 613 | [[package]] 614 | name = "html2md" 615 | version = "0.2.14" 616 | source = "registry+https://github.com/rust-lang/crates.io-index" 617 | checksum = "be92446e11d68f5d71367d571c229d09ced1f24ab6d08ea0bff329d5f6c0b2a3" 618 | dependencies = [ 619 | "html5ever", 620 | "jni", 621 | "lazy_static", 622 | "markup5ever_rcdom", 623 | "percent-encoding", 624 | "regex", 625 | ] 626 | 627 | [[package]] 628 | name = "html5ever" 629 | version = "0.26.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" 632 | dependencies = [ 633 | "log", 634 | "mac", 635 | "markup5ever", 636 | "proc-macro2", 637 | "quote", 638 | "syn 1.0.109", 639 | ] 640 | 641 | [[package]] 642 | name = "iana-time-zone" 643 | version = "0.1.58" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" 646 | dependencies = [ 647 | "android_system_properties", 648 | "core-foundation-sys", 649 | "iana-time-zone-haiku", 650 | "js-sys", 651 | "wasm-bindgen", 652 | "windows-core", 653 | ] 654 | 655 | [[package]] 656 | name = "iana-time-zone-haiku" 657 | version = "0.1.2" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 660 | dependencies = [ 661 | "cc", 662 | ] 663 | 664 | [[package]] 665 | name = "idna" 666 | version = "0.5.0" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 669 | dependencies = [ 670 | "unicode-bidi", 671 | "unicode-normalization", 672 | ] 673 | 674 | [[package]] 675 | name = "indexmap" 676 | version = "1.9.3" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 679 | dependencies = [ 680 | "autocfg", 681 | "hashbrown", 682 | ] 683 | 684 | [[package]] 685 | name = "itoa" 686 | version = "1.0.9" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 689 | 690 | [[package]] 691 | name = "jni" 692 | version = "0.19.0" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" 695 | dependencies = [ 696 | "cesu8", 697 | "combine", 698 | "jni-sys", 699 | "log", 700 | "thiserror", 701 | "walkdir", 702 | ] 703 | 704 | [[package]] 705 | name = "jni-sys" 706 | version = "0.3.0" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" 709 | 710 | [[package]] 711 | name = "js-sys" 712 | version = "0.3.66" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" 715 | dependencies = [ 716 | "wasm-bindgen", 717 | ] 718 | 719 | [[package]] 720 | name = "lazy_static" 721 | version = "1.4.0" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 724 | 725 | [[package]] 726 | name = "libc" 727 | version = "0.2.150" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" 730 | 731 | [[package]] 732 | name = "libredox" 733 | version = "0.0.1" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" 736 | dependencies = [ 737 | "bitflags 2.4.1", 738 | "libc", 739 | "redox_syscall 0.4.1", 740 | ] 741 | 742 | [[package]] 743 | name = "libsqlite3-sys" 744 | version = "0.20.1" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "64d31059f22935e6c31830db5249ba2b7ecd54fd73a9909286f0a67aa55c2fbd" 747 | dependencies = [ 748 | "cc", 749 | "pkg-config", 750 | "vcpkg", 751 | ] 752 | 753 | [[package]] 754 | name = "linux-raw-sys" 755 | version = "0.4.12" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" 758 | 759 | [[package]] 760 | name = "lock_api" 761 | version = "0.3.4" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" 764 | dependencies = [ 765 | "scopeguard", 766 | ] 767 | 768 | [[package]] 769 | name = "lock_api" 770 | version = "0.4.11" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 773 | dependencies = [ 774 | "autocfg", 775 | "scopeguard", 776 | ] 777 | 778 | [[package]] 779 | name = "log" 780 | version = "0.4.20" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 783 | 784 | [[package]] 785 | name = "mac" 786 | version = "0.1.1" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 789 | 790 | [[package]] 791 | name = "markup5ever" 792 | version = "0.11.0" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" 795 | dependencies = [ 796 | "log", 797 | "phf", 798 | "phf_codegen", 799 | "string_cache", 800 | "string_cache_codegen", 801 | "tendril", 802 | ] 803 | 804 | [[package]] 805 | name = "markup5ever_rcdom" 806 | version = "0.2.0" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "b9521dd6750f8e80ee6c53d65e2e4656d7de37064f3a7a5d2d11d05df93839c2" 809 | dependencies = [ 810 | "html5ever", 811 | "markup5ever", 812 | "tendril", 813 | "xml5ever", 814 | ] 815 | 816 | [[package]] 817 | name = "memchr" 818 | version = "2.6.4" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" 821 | 822 | [[package]] 823 | name = "memoffset" 824 | version = "0.9.0" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 827 | dependencies = [ 828 | "autocfg", 829 | ] 830 | 831 | [[package]] 832 | name = "minimad" 833 | version = "0.6.9" 834 | source = "registry+https://github.com/rust-lang/crates.io-index" 835 | checksum = "cb5ed7ea8b54916318ac7ec6ff06b2b428fdf9cb54d1867714f699dbd1659ad4" 836 | dependencies = [ 837 | "lazy_static", 838 | ] 839 | 840 | [[package]] 841 | name = "miniz_oxide" 842 | version = "0.7.1" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 845 | dependencies = [ 846 | "adler", 847 | ] 848 | 849 | [[package]] 850 | name = "mio" 851 | version = "0.7.14" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" 854 | dependencies = [ 855 | "libc", 856 | "log", 857 | "miow", 858 | "ntapi", 859 | "winapi", 860 | ] 861 | 862 | [[package]] 863 | name = "miow" 864 | version = "0.3.7" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 867 | dependencies = [ 868 | "winapi", 869 | ] 870 | 871 | [[package]] 872 | name = "new_debug_unreachable" 873 | version = "1.0.4" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" 876 | 877 | [[package]] 878 | name = "ntapi" 879 | version = "0.3.7" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" 882 | dependencies = [ 883 | "winapi", 884 | ] 885 | 886 | [[package]] 887 | name = "num-traits" 888 | version = "0.2.17" 889 | source = "registry+https://github.com/rust-lang/crates.io-index" 890 | checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" 891 | dependencies = [ 892 | "autocfg", 893 | ] 894 | 895 | [[package]] 896 | name = "object" 897 | version = "0.32.1" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" 900 | dependencies = [ 901 | "memchr", 902 | ] 903 | 904 | [[package]] 905 | name = "once_cell" 906 | version = "1.19.0" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 909 | 910 | [[package]] 911 | name = "os_str_bytes" 912 | version = "6.6.1" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" 915 | 916 | [[package]] 917 | name = "parking_lot" 918 | version = "0.10.2" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" 921 | dependencies = [ 922 | "lock_api 0.3.4", 923 | "parking_lot_core 0.7.3", 924 | ] 925 | 926 | [[package]] 927 | name = "parking_lot" 928 | version = "0.12.1" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 931 | dependencies = [ 932 | "lock_api 0.4.11", 933 | "parking_lot_core 0.9.9", 934 | ] 935 | 936 | [[package]] 937 | name = "parking_lot_core" 938 | version = "0.7.3" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "b93f386bb233083c799e6e642a9d73db98c24a5deeb95ffc85bf281255dffc98" 941 | dependencies = [ 942 | "cfg-if 0.1.10", 943 | "cloudabi", 944 | "libc", 945 | "redox_syscall 0.1.57", 946 | "smallvec", 947 | "winapi", 948 | ] 949 | 950 | [[package]] 951 | name = "parking_lot_core" 952 | version = "0.9.9" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" 955 | dependencies = [ 956 | "cfg-if 1.0.0", 957 | "libc", 958 | "redox_syscall 0.4.1", 959 | "smallvec", 960 | "windows-targets 0.48.5", 961 | ] 962 | 963 | [[package]] 964 | name = "percent-encoding" 965 | version = "2.3.1" 966 | source = "registry+https://github.com/rust-lang/crates.io-index" 967 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 968 | 969 | [[package]] 970 | name = "phf" 971 | version = "0.10.1" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" 974 | dependencies = [ 975 | "phf_shared", 976 | ] 977 | 978 | [[package]] 979 | name = "phf_codegen" 980 | version = "0.10.0" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" 983 | dependencies = [ 984 | "phf_generator", 985 | "phf_shared", 986 | ] 987 | 988 | [[package]] 989 | name = "phf_generator" 990 | version = "0.10.0" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" 993 | dependencies = [ 994 | "phf_shared", 995 | "rand", 996 | ] 997 | 998 | [[package]] 999 | name = "phf_shared" 1000 | version = "0.10.0" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" 1003 | dependencies = [ 1004 | "siphasher", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "pkg-config" 1009 | version = "0.3.27" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" 1012 | 1013 | [[package]] 1014 | name = "ppv-lite86" 1015 | version = "0.2.17" 1016 | source = "registry+https://github.com/rust-lang/crates.io-index" 1017 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1018 | 1019 | [[package]] 1020 | name = "precomputed-hash" 1021 | version = "0.1.1" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 1024 | 1025 | [[package]] 1026 | name = "proc-macro-error" 1027 | version = "1.0.4" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1030 | dependencies = [ 1031 | "proc-macro-error-attr", 1032 | "proc-macro2", 1033 | "quote", 1034 | "syn 1.0.109", 1035 | "version_check", 1036 | ] 1037 | 1038 | [[package]] 1039 | name = "proc-macro-error-attr" 1040 | version = "1.0.4" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1043 | dependencies = [ 1044 | "proc-macro2", 1045 | "quote", 1046 | "version_check", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "proc-macro2" 1051 | version = "1.0.70" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" 1054 | dependencies = [ 1055 | "unicode-ident", 1056 | ] 1057 | 1058 | [[package]] 1059 | name = "quote" 1060 | version = "1.0.33" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 1063 | dependencies = [ 1064 | "proc-macro2", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "rand" 1069 | version = "0.8.5" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1072 | dependencies = [ 1073 | "libc", 1074 | "rand_chacha", 1075 | "rand_core", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "rand_chacha" 1080 | version = "0.3.1" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1083 | dependencies = [ 1084 | "ppv-lite86", 1085 | "rand_core", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "rand_core" 1090 | version = "0.6.4" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1093 | dependencies = [ 1094 | "getrandom", 1095 | ] 1096 | 1097 | [[package]] 1098 | name = "redox_syscall" 1099 | version = "0.1.57" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 1102 | 1103 | [[package]] 1104 | name = "redox_syscall" 1105 | version = "0.4.1" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 1108 | dependencies = [ 1109 | "bitflags 1.3.2", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "redox_users" 1114 | version = "0.4.4" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" 1117 | dependencies = [ 1118 | "getrandom", 1119 | "libredox", 1120 | "thiserror", 1121 | ] 1122 | 1123 | [[package]] 1124 | name = "regex" 1125 | version = "1.10.2" 1126 | source = "registry+https://github.com/rust-lang/crates.io-index" 1127 | checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" 1128 | dependencies = [ 1129 | "aho-corasick", 1130 | "memchr", 1131 | "regex-automata", 1132 | "regex-syntax", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "regex-automata" 1137 | version = "0.4.3" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" 1140 | dependencies = [ 1141 | "aho-corasick", 1142 | "memchr", 1143 | "regex-syntax", 1144 | ] 1145 | 1146 | [[package]] 1147 | name = "regex-syntax" 1148 | version = "0.8.2" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" 1151 | 1152 | [[package]] 1153 | name = "ring" 1154 | version = "0.17.7" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" 1157 | dependencies = [ 1158 | "cc", 1159 | "getrandom", 1160 | "libc", 1161 | "spin", 1162 | "untrusted", 1163 | "windows-sys 0.48.0", 1164 | ] 1165 | 1166 | [[package]] 1167 | name = "rustc-demangle" 1168 | version = "0.1.23" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 1171 | 1172 | [[package]] 1173 | name = "rustix" 1174 | version = "0.38.26" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" 1177 | dependencies = [ 1178 | "bitflags 2.4.1", 1179 | "errno", 1180 | "libc", 1181 | "linux-raw-sys", 1182 | "windows-sys 0.52.0", 1183 | ] 1184 | 1185 | [[package]] 1186 | name = "rustls" 1187 | version = "0.21.9" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" 1190 | dependencies = [ 1191 | "log", 1192 | "ring", 1193 | "rustls-webpki", 1194 | "sct", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "rustls-webpki" 1199 | version = "0.101.7" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" 1202 | dependencies = [ 1203 | "ring", 1204 | "untrusted", 1205 | ] 1206 | 1207 | [[package]] 1208 | name = "ryu" 1209 | version = "1.0.15" 1210 | source = "registry+https://github.com/rust-lang/crates.io-index" 1211 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 1212 | 1213 | [[package]] 1214 | name = "same-file" 1215 | version = "1.0.6" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1218 | dependencies = [ 1219 | "winapi-util", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "scopeguard" 1224 | version = "1.2.0" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1227 | 1228 | [[package]] 1229 | name = "sct" 1230 | version = "0.7.1" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" 1233 | dependencies = [ 1234 | "ring", 1235 | "untrusted", 1236 | ] 1237 | 1238 | [[package]] 1239 | name = "serde" 1240 | version = "1.0.193" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" 1243 | dependencies = [ 1244 | "serde_derive", 1245 | ] 1246 | 1247 | [[package]] 1248 | name = "serde_derive" 1249 | version = "1.0.193" 1250 | source = "registry+https://github.com/rust-lang/crates.io-index" 1251 | checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" 1252 | dependencies = [ 1253 | "proc-macro2", 1254 | "quote", 1255 | "syn 2.0.39", 1256 | ] 1257 | 1258 | [[package]] 1259 | name = "serde_json" 1260 | version = "1.0.108" 1261 | source = "registry+https://github.com/rust-lang/crates.io-index" 1262 | checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" 1263 | dependencies = [ 1264 | "itoa", 1265 | "ryu", 1266 | "serde", 1267 | ] 1268 | 1269 | [[package]] 1270 | name = "signal-hook" 1271 | version = "0.1.17" 1272 | source = "registry+https://github.com/rust-lang/crates.io-index" 1273 | checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" 1274 | dependencies = [ 1275 | "libc", 1276 | "mio", 1277 | "signal-hook-registry", 1278 | ] 1279 | 1280 | [[package]] 1281 | name = "signal-hook-registry" 1282 | version = "1.4.1" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" 1285 | dependencies = [ 1286 | "libc", 1287 | ] 1288 | 1289 | [[package]] 1290 | name = "siphasher" 1291 | version = "0.3.11" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 1294 | 1295 | [[package]] 1296 | name = "smallvec" 1297 | version = "1.11.2" 1298 | source = "registry+https://github.com/rust-lang/crates.io-index" 1299 | checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" 1300 | 1301 | [[package]] 1302 | name = "spin" 1303 | version = "0.9.8" 1304 | source = "registry+https://github.com/rust-lang/crates.io-index" 1305 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1306 | 1307 | [[package]] 1308 | name = "string_cache" 1309 | version = "0.8.7" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" 1312 | dependencies = [ 1313 | "new_debug_unreachable", 1314 | "once_cell", 1315 | "parking_lot 0.12.1", 1316 | "phf_shared", 1317 | "precomputed-hash", 1318 | "serde", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "string_cache_codegen" 1323 | version = "0.5.2" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" 1326 | dependencies = [ 1327 | "phf_generator", 1328 | "phf_shared", 1329 | "proc-macro2", 1330 | "quote", 1331 | ] 1332 | 1333 | [[package]] 1334 | name = "strsim" 1335 | version = "0.10.0" 1336 | source = "registry+https://github.com/rust-lang/crates.io-index" 1337 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1338 | 1339 | [[package]] 1340 | name = "syn" 1341 | version = "1.0.109" 1342 | source = "registry+https://github.com/rust-lang/crates.io-index" 1343 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1344 | dependencies = [ 1345 | "proc-macro2", 1346 | "quote", 1347 | "unicode-ident", 1348 | ] 1349 | 1350 | [[package]] 1351 | name = "syn" 1352 | version = "2.0.39" 1353 | source = "registry+https://github.com/rust-lang/crates.io-index" 1354 | checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" 1355 | dependencies = [ 1356 | "proc-macro2", 1357 | "quote", 1358 | "unicode-ident", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "synstructure" 1363 | version = "0.12.6" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" 1366 | dependencies = [ 1367 | "proc-macro2", 1368 | "quote", 1369 | "syn 1.0.109", 1370 | "unicode-xid", 1371 | ] 1372 | 1373 | [[package]] 1374 | name = "tempfile" 1375 | version = "3.8.1" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" 1378 | dependencies = [ 1379 | "cfg-if 1.0.0", 1380 | "fastrand", 1381 | "redox_syscall 0.4.1", 1382 | "rustix", 1383 | "windows-sys 0.48.0", 1384 | ] 1385 | 1386 | [[package]] 1387 | name = "tendril" 1388 | version = "0.4.3" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" 1391 | dependencies = [ 1392 | "futf", 1393 | "mac", 1394 | "utf-8", 1395 | ] 1396 | 1397 | [[package]] 1398 | name = "termcolor" 1399 | version = "1.4.0" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" 1402 | dependencies = [ 1403 | "winapi-util", 1404 | ] 1405 | 1406 | [[package]] 1407 | name = "termimad" 1408 | version = "0.9.7" 1409 | source = "registry+https://github.com/rust-lang/crates.io-index" 1410 | checksum = "8f920a3d35c4070ab26eba20a87053526697fdace80ac3d821bb6d7504f32dfc" 1411 | dependencies = [ 1412 | "crossbeam", 1413 | "crossterm", 1414 | "lazy_static", 1415 | "minimad", 1416 | "thiserror", 1417 | "unicode-width", 1418 | ] 1419 | 1420 | [[package]] 1421 | name = "textwrap" 1422 | version = "0.16.0" 1423 | source = "registry+https://github.com/rust-lang/crates.io-index" 1424 | checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" 1425 | 1426 | [[package]] 1427 | name = "thiserror" 1428 | version = "1.0.50" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" 1431 | dependencies = [ 1432 | "thiserror-impl", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "thiserror-impl" 1437 | version = "1.0.50" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" 1440 | dependencies = [ 1441 | "proc-macro2", 1442 | "quote", 1443 | "syn 2.0.39", 1444 | ] 1445 | 1446 | [[package]] 1447 | name = "tinyvec" 1448 | version = "1.6.0" 1449 | source = "registry+https://github.com/rust-lang/crates.io-index" 1450 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1451 | dependencies = [ 1452 | "tinyvec_macros", 1453 | ] 1454 | 1455 | [[package]] 1456 | name = "tinyvec_macros" 1457 | version = "0.1.1" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1460 | 1461 | [[package]] 1462 | name = "toml" 1463 | version = "0.5.11" 1464 | source = "registry+https://github.com/rust-lang/crates.io-index" 1465 | checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 1466 | dependencies = [ 1467 | "serde", 1468 | ] 1469 | 1470 | [[package]] 1471 | name = "unicode-bidi" 1472 | version = "0.3.14" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" 1475 | 1476 | [[package]] 1477 | name = "unicode-ident" 1478 | version = "1.0.12" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1481 | 1482 | [[package]] 1483 | name = "unicode-normalization" 1484 | version = "0.1.22" 1485 | source = "registry+https://github.com/rust-lang/crates.io-index" 1486 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1487 | dependencies = [ 1488 | "tinyvec", 1489 | ] 1490 | 1491 | [[package]] 1492 | name = "unicode-width" 1493 | version = "0.1.11" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" 1496 | 1497 | [[package]] 1498 | name = "unicode-xid" 1499 | version = "0.2.4" 1500 | source = "registry+https://github.com/rust-lang/crates.io-index" 1501 | checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" 1502 | 1503 | [[package]] 1504 | name = "untrusted" 1505 | version = "0.9.0" 1506 | source = "registry+https://github.com/rust-lang/crates.io-index" 1507 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1508 | 1509 | [[package]] 1510 | name = "ureq" 1511 | version = "2.9.1" 1512 | source = "registry+https://github.com/rust-lang/crates.io-index" 1513 | checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97" 1514 | dependencies = [ 1515 | "base64", 1516 | "flate2", 1517 | "log", 1518 | "once_cell", 1519 | "rustls", 1520 | "rustls-webpki", 1521 | "url", 1522 | "webpki-roots", 1523 | ] 1524 | 1525 | [[package]] 1526 | name = "url" 1527 | version = "2.5.0" 1528 | source = "registry+https://github.com/rust-lang/crates.io-index" 1529 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 1530 | dependencies = [ 1531 | "form_urlencoded", 1532 | "idna", 1533 | "percent-encoding", 1534 | ] 1535 | 1536 | [[package]] 1537 | name = "utf-8" 1538 | version = "0.7.6" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1541 | 1542 | [[package]] 1543 | name = "utf8parse" 1544 | version = "0.2.1" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 1547 | 1548 | [[package]] 1549 | name = "vcpkg" 1550 | version = "0.2.15" 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" 1552 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1553 | 1554 | [[package]] 1555 | name = "version_check" 1556 | version = "0.9.4" 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" 1558 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1559 | 1560 | [[package]] 1561 | name = "walkdir" 1562 | version = "2.4.0" 1563 | source = "registry+https://github.com/rust-lang/crates.io-index" 1564 | checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" 1565 | dependencies = [ 1566 | "same-file", 1567 | "winapi-util", 1568 | ] 1569 | 1570 | [[package]] 1571 | name = "wasi" 1572 | version = "0.11.0+wasi-snapshot-preview1" 1573 | source = "registry+https://github.com/rust-lang/crates.io-index" 1574 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1575 | 1576 | [[package]] 1577 | name = "wasm-bindgen" 1578 | version = "0.2.89" 1579 | source = "registry+https://github.com/rust-lang/crates.io-index" 1580 | checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" 1581 | dependencies = [ 1582 | "cfg-if 1.0.0", 1583 | "wasm-bindgen-macro", 1584 | ] 1585 | 1586 | [[package]] 1587 | name = "wasm-bindgen-backend" 1588 | version = "0.2.89" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" 1591 | dependencies = [ 1592 | "bumpalo", 1593 | "log", 1594 | "once_cell", 1595 | "proc-macro2", 1596 | "quote", 1597 | "syn 2.0.39", 1598 | "wasm-bindgen-shared", 1599 | ] 1600 | 1601 | [[package]] 1602 | name = "wasm-bindgen-macro" 1603 | version = "0.2.89" 1604 | source = "registry+https://github.com/rust-lang/crates.io-index" 1605 | checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" 1606 | dependencies = [ 1607 | "quote", 1608 | "wasm-bindgen-macro-support", 1609 | ] 1610 | 1611 | [[package]] 1612 | name = "wasm-bindgen-macro-support" 1613 | version = "0.2.89" 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" 1615 | checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" 1616 | dependencies = [ 1617 | "proc-macro2", 1618 | "quote", 1619 | "syn 2.0.39", 1620 | "wasm-bindgen-backend", 1621 | "wasm-bindgen-shared", 1622 | ] 1623 | 1624 | [[package]] 1625 | name = "wasm-bindgen-shared" 1626 | version = "0.2.89" 1627 | source = "registry+https://github.com/rust-lang/crates.io-index" 1628 | checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" 1629 | 1630 | [[package]] 1631 | name = "web-sys" 1632 | version = "0.3.66" 1633 | source = "registry+https://github.com/rust-lang/crates.io-index" 1634 | checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" 1635 | dependencies = [ 1636 | "js-sys", 1637 | "wasm-bindgen", 1638 | ] 1639 | 1640 | [[package]] 1641 | name = "webbrowser" 1642 | version = "0.5.5" 1643 | source = "registry+https://github.com/rust-lang/crates.io-index" 1644 | checksum = "ecad156490d6b620308ed411cfee90d280b3cbd13e189ea0d3fada8acc89158a" 1645 | dependencies = [ 1646 | "web-sys", 1647 | "widestring", 1648 | "winapi", 1649 | ] 1650 | 1651 | [[package]] 1652 | name = "webpki-roots" 1653 | version = "0.25.3" 1654 | source = "registry+https://github.com/rust-lang/crates.io-index" 1655 | checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" 1656 | 1657 | [[package]] 1658 | name = "widestring" 1659 | version = "0.4.3" 1660 | source = "registry+https://github.com/rust-lang/crates.io-index" 1661 | checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" 1662 | 1663 | [[package]] 1664 | name = "winapi" 1665 | version = "0.3.9" 1666 | source = "registry+https://github.com/rust-lang/crates.io-index" 1667 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1668 | dependencies = [ 1669 | "winapi-i686-pc-windows-gnu", 1670 | "winapi-x86_64-pc-windows-gnu", 1671 | ] 1672 | 1673 | [[package]] 1674 | name = "winapi-i686-pc-windows-gnu" 1675 | version = "0.4.0" 1676 | source = "registry+https://github.com/rust-lang/crates.io-index" 1677 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1678 | 1679 | [[package]] 1680 | name = "winapi-util" 1681 | version = "0.1.6" 1682 | source = "registry+https://github.com/rust-lang/crates.io-index" 1683 | checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" 1684 | dependencies = [ 1685 | "winapi", 1686 | ] 1687 | 1688 | [[package]] 1689 | name = "winapi-x86_64-pc-windows-gnu" 1690 | version = "0.4.0" 1691 | source = "registry+https://github.com/rust-lang/crates.io-index" 1692 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1693 | 1694 | [[package]] 1695 | name = "windows-core" 1696 | version = "0.51.1" 1697 | source = "registry+https://github.com/rust-lang/crates.io-index" 1698 | checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" 1699 | dependencies = [ 1700 | "windows-targets 0.48.5", 1701 | ] 1702 | 1703 | [[package]] 1704 | name = "windows-sys" 1705 | version = "0.48.0" 1706 | source = "registry+https://github.com/rust-lang/crates.io-index" 1707 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1708 | dependencies = [ 1709 | "windows-targets 0.48.5", 1710 | ] 1711 | 1712 | [[package]] 1713 | name = "windows-sys" 1714 | version = "0.52.0" 1715 | source = "registry+https://github.com/rust-lang/crates.io-index" 1716 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1717 | dependencies = [ 1718 | "windows-targets 0.52.0", 1719 | ] 1720 | 1721 | [[package]] 1722 | name = "windows-targets" 1723 | version = "0.48.5" 1724 | source = "registry+https://github.com/rust-lang/crates.io-index" 1725 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1726 | dependencies = [ 1727 | "windows_aarch64_gnullvm 0.48.5", 1728 | "windows_aarch64_msvc 0.48.5", 1729 | "windows_i686_gnu 0.48.5", 1730 | "windows_i686_msvc 0.48.5", 1731 | "windows_x86_64_gnu 0.48.5", 1732 | "windows_x86_64_gnullvm 0.48.5", 1733 | "windows_x86_64_msvc 0.48.5", 1734 | ] 1735 | 1736 | [[package]] 1737 | name = "windows-targets" 1738 | version = "0.52.0" 1739 | source = "registry+https://github.com/rust-lang/crates.io-index" 1740 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 1741 | dependencies = [ 1742 | "windows_aarch64_gnullvm 0.52.0", 1743 | "windows_aarch64_msvc 0.52.0", 1744 | "windows_i686_gnu 0.52.0", 1745 | "windows_i686_msvc 0.52.0", 1746 | "windows_x86_64_gnu 0.52.0", 1747 | "windows_x86_64_gnullvm 0.52.0", 1748 | "windows_x86_64_msvc 0.52.0", 1749 | ] 1750 | 1751 | [[package]] 1752 | name = "windows_aarch64_gnullvm" 1753 | version = "0.48.5" 1754 | source = "registry+https://github.com/rust-lang/crates.io-index" 1755 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1756 | 1757 | [[package]] 1758 | name = "windows_aarch64_gnullvm" 1759 | version = "0.52.0" 1760 | source = "registry+https://github.com/rust-lang/crates.io-index" 1761 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 1762 | 1763 | [[package]] 1764 | name = "windows_aarch64_msvc" 1765 | version = "0.48.5" 1766 | source = "registry+https://github.com/rust-lang/crates.io-index" 1767 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1768 | 1769 | [[package]] 1770 | name = "windows_aarch64_msvc" 1771 | version = "0.52.0" 1772 | source = "registry+https://github.com/rust-lang/crates.io-index" 1773 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 1774 | 1775 | [[package]] 1776 | name = "windows_i686_gnu" 1777 | version = "0.48.5" 1778 | source = "registry+https://github.com/rust-lang/crates.io-index" 1779 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1780 | 1781 | [[package]] 1782 | name = "windows_i686_gnu" 1783 | version = "0.52.0" 1784 | source = "registry+https://github.com/rust-lang/crates.io-index" 1785 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 1786 | 1787 | [[package]] 1788 | name = "windows_i686_msvc" 1789 | version = "0.48.5" 1790 | source = "registry+https://github.com/rust-lang/crates.io-index" 1791 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1792 | 1793 | [[package]] 1794 | name = "windows_i686_msvc" 1795 | version = "0.52.0" 1796 | source = "registry+https://github.com/rust-lang/crates.io-index" 1797 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 1798 | 1799 | [[package]] 1800 | name = "windows_x86_64_gnu" 1801 | version = "0.48.5" 1802 | source = "registry+https://github.com/rust-lang/crates.io-index" 1803 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1804 | 1805 | [[package]] 1806 | name = "windows_x86_64_gnu" 1807 | version = "0.52.0" 1808 | source = "registry+https://github.com/rust-lang/crates.io-index" 1809 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 1810 | 1811 | [[package]] 1812 | name = "windows_x86_64_gnullvm" 1813 | version = "0.48.5" 1814 | source = "registry+https://github.com/rust-lang/crates.io-index" 1815 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1816 | 1817 | [[package]] 1818 | name = "windows_x86_64_gnullvm" 1819 | version = "0.52.0" 1820 | source = "registry+https://github.com/rust-lang/crates.io-index" 1821 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 1822 | 1823 | [[package]] 1824 | name = "windows_x86_64_msvc" 1825 | version = "0.48.5" 1826 | source = "registry+https://github.com/rust-lang/crates.io-index" 1827 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1828 | 1829 | [[package]] 1830 | name = "windows_x86_64_msvc" 1831 | version = "0.52.0" 1832 | source = "registry+https://github.com/rust-lang/crates.io-index" 1833 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 1834 | 1835 | [[package]] 1836 | name = "xml5ever" 1837 | version = "0.17.0" 1838 | source = "registry+https://github.com/rust-lang/crates.io-index" 1839 | checksum = "4034e1d05af98b51ad7214527730626f019682d797ba38b51689212118d8e650" 1840 | dependencies = [ 1841 | "log", 1842 | "mac", 1843 | "markup5ever", 1844 | ] 1845 | --------------------------------------------------------------------------------