From 111cefe8f145012d461d28d7797921b65ac857e1 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 12 Oct 2024 21:29:39 +1000 Subject: [PATCH 001/113] Revert "When updating all FSRS parameters at once, exclude suspended cards" https://forums.ankiweb.net/t/memory-state-of-suspended-cards/50460/6 This reverts commit 656cfe0b9cbecb6d669ccf02d6e8364400f37121. --- rslib/src/deckconfig/update.rs | 5 +---- rslib/src/scheduler/fsrs/memory_state.rs | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/rslib/src/deckconfig/update.rs b/rslib/src/deckconfig/update.rs index fe7121425..dc68b8a39 100644 --- a/rslib/src/deckconfig/update.rs +++ b/rslib/src/deckconfig/update.rs @@ -262,12 +262,9 @@ impl Collection { None } }); - let search = SearchNode::DeckIdsWithoutChildren(comma_separated_ids(&search)) - .and(SearchNode::State(StateKind::Suspended).negated()) - .try_into_search()?; Ok(UpdateMemoryStateEntry { req: weights, - search, + search: SearchNode::DeckIdsWithoutChildren(comma_separated_ids(&search)), ignore_before: config .map(ignore_revlogs_before_ms_from_config) .unwrap_or(Ok(0.into()))?, diff --git a/rslib/src/scheduler/fsrs/memory_state.rs b/rslib/src/scheduler/fsrs/memory_state.rs index ce20d8925..977368379 100644 --- a/rslib/src/scheduler/fsrs/memory_state.rs +++ b/rslib/src/scheduler/fsrs/memory_state.rs @@ -18,7 +18,6 @@ use crate::scheduler::fsrs::weights::single_card_revlog_to_items; use crate::scheduler::fsrs::weights::Weights; use crate::scheduler::states::fuzz::with_review_fuzz; use crate::search::Negated; -use crate::search::Node; use crate::search::SearchNode; use crate::search::StateKind; @@ -39,7 +38,7 @@ pub(crate) struct UpdateMemoryStateRequest { pub(crate) struct UpdateMemoryStateEntry { pub req: Option, - pub search: Node, + pub search: SearchNode, pub ignore_before: TimestampMillis, } @@ -61,7 +60,8 @@ impl Collection { ignore_before, } in entries { - let search = SearchBuilder::all([search, SearchNode::State(StateKind::New).negated()]); + let search = + SearchBuilder::all([search.into(), SearchNode::State(StateKind::New).negated()]); let revlog = self.revlog_for_srs(search)?; let reschedule = req.as_ref().map(|e| e.reschedule).unwrap_or_default(); let last_revlog_info = if reschedule { From e77632d7b213f61225697c2134d74379d561ff99 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 15 Oct 2024 21:32:46 +1000 Subject: [PATCH 002/113] Fix UI hanging when update check stalls https://forums.ankiweb.net/t/anki-24-10-beta/49989/222 --- qt/aqt/update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/aqt/update.py b/qt/aqt/update.py index 1b60ded48..fd0e4eafd 100644 --- a/qt/aqt/update.py +++ b/qt/aqt/update.py @@ -52,7 +52,7 @@ def check_for_update() -> None: QueryOp(parent=mw, op=do_check, success=on_done).failure( on_fail - ).run_in_background() + ).without_collection().run_in_background() def prompt_to_update(mw: aqt.AnkiQt, ver: str) -> None: From 743017b471f9e989e90012ae607febb237354dc1 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 15 Oct 2024 23:00:38 +1000 Subject: [PATCH 003/113] Partially switch to File::set_times() from utime crate --- rslib/io/src/error.rs | 2 ++ rslib/io/src/lib.rs | 17 +++++++++++++++++ rslib/src/media/files.rs | 10 +++++----- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/rslib/io/src/error.rs b/rslib/io/src/error.rs index 6df493940..c66a29a41 100644 --- a/rslib/io/src/error.rs +++ b/rslib/io/src/error.rs @@ -35,6 +35,7 @@ pub enum FileOp { Sync, Metadata, DecodeUtf8Filename, + SetFileTimes, /// For legacy errors without any context. Unknown, } @@ -61,6 +62,7 @@ impl FileIoError { FileOp::Sync => "sync".into(), FileOp::Metadata => "get metadata".into(), FileOp::DecodeUtf8Filename => "decode utf8 filename".into(), + FileOp::SetFileTimes => "set file times".into(), }, self.path.to_string_lossy(), self.source diff --git a/rslib/io/src/lib.rs b/rslib/io/src/lib.rs index 7420da3cb..f9ee9758a 100644 --- a/rslib/io/src/lib.rs +++ b/rslib/io/src/lib.rs @@ -4,6 +4,8 @@ mod error; use std::fs::File; +use std::fs::FileTimes; +use std::fs::OpenOptions; use std::io::Read; use std::io::Seek; use std::path::Component; @@ -37,6 +39,13 @@ pub fn open_file(path: impl AsRef) -> Result { }) } +pub fn open_file_ext(path: impl AsRef, options: OpenOptions) -> Result { + options.open(&path).context(FileIoSnafu { + path: path.as_ref(), + op: FileOp::Open, + }) +} + /// See [std::fs::write]. pub fn write_file(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result<()> { std::fs::write(&path, contents).context(FileIoSnafu { @@ -44,6 +53,14 @@ pub fn write_file(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result< op: FileOp::Write, }) } +/// See [File::set_times]. Note that this won't work on folders. +pub fn set_file_times(path: impl AsRef, times: FileTimes) -> Result<()> { + let file = open_file_ext(&path, OpenOptions::new().write(true).to_owned())?; + file.set_times(times).context(FileIoSnafu { + path: path.as_ref(), + op: FileOp::SetFileTimes, + }) +} /// See [std::fs::remove_file]. #[allow(dead_code)] diff --git a/rslib/src/media/files.rs b/rslib/src/media/files.rs index 2cbef1a89..9fd3bc85f 100644 --- a/rslib/src/media/files.rs +++ b/rslib/src/media/files.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::fs; +use std::fs::FileTimes; use std::io; use std::io::Read; use std::path::Path; @@ -12,6 +13,7 @@ use std::time; use anki_io::create_dir; use anki_io::open_file; +use anki_io::set_file_times; use anki_io::write_file; use anki_io::FileIoError; use anki_io::FileIoSnafu; @@ -345,11 +347,9 @@ where fs::rename(&src_path, &dst_path)?; // mark it as modified, so we can expire it in the future - let secs = time::SystemTime::now() - .duration_since(time::UNIX_EPOCH) - .unwrap() - .as_secs() as i64; - if let Err(err) = utime::set_file_times(&dst_path, secs, secs) { + let secs = time::SystemTime::now(); + let times = FileTimes::new().set_accessed(secs).set_modified(secs); + if let Err(err) = set_file_times(&dst_path, times) { // The libc utimes() call fails on (some? all?) Android devices. Since we don't // do automatic expiry yet, we can safely ignore the error. if !cfg!(target_os = "android") { From b75fd94c963d09051b6572aeb2a47b6069455767 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 15 Oct 2024 22:59:30 +1000 Subject: [PATCH 004/113] Update Rust deps - Primarily for the latest RUSTSEC on pyo3 - utime has been pinned, as they've introduced a deprecation warning without a solution being available for folder mtimes --- Cargo.lock | 637 +++++++++--------- Cargo.toml | 2 +- cargo/licenses.json | 199 +++--- .../media/database/client/changetracker.rs | 2 + 4 files changed, 427 insertions(+), 413 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f0673c568..ea3c70c7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -148,9 +148,9 @@ dependencies = [ "pulldown-cmark 0.9.6", "rand", "regex", - "reqwest 0.12.7", + "reqwest 0.12.8", "rusqlite", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "scopeguard", "serde", "serde-aux", @@ -160,7 +160,7 @@ dependencies = [ "sha1", "snafu", "strum 0.26.3", - "syn 2.0.77", + "syn 2.0.79", "tempfile", "tokio", "tokio-util", @@ -305,9 +305,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "apple-bundles" @@ -323,9 +323,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -354,9 +354,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.12" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +checksum = "e26a9844c659a2a293d239c7910b752f8487fe122c6c8bd1659bf85a6507c302" dependencies = [ "futures-core", "memchr", @@ -368,9 +368,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -379,24 +379,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -407,15 +407,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -449,9 +449,9 @@ dependencies = [ [[package]] name = "axum-client-ip" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72188bed20deb981f3a4a9fe674e5980fd9e9c2bd880baa94715ad5d60d64c67" +checksum = "9eefda7e2b27e1bda4d6fa8a06b50803b8793769045918bc37ad062d48a6efac" dependencies = [ "axum", "forwarded-header-value", @@ -460,9 +460,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -473,7 +473,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -481,9 +481,9 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733" +checksum = "73c3220b188aea709cf1b6c5f9b01c3bd936bb08bd2b5184a12b35ac8131b1f9" dependencies = [ "axum", "axum-core", @@ -504,29 +504,28 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" +checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ - "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide 0.8.0", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -639,7 +638,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", - "regex-automata 0.4.7", + "regex-automata 0.4.8", "serde", ] @@ -782,7 +781,7 @@ dependencies = [ "derive-new", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -906,22 +905,22 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -932,9 +931,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "bzip2" @@ -978,7 +977,7 @@ dependencies = [ "rand", "rand_distr", "rayon", - "safetensors 0.4.4", + "safetensors 0.4.5", "thiserror", "yoke", "zip", @@ -1001,9 +1000,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.15" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", @@ -1073,9 +1072,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -1083,9 +1082,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -1096,23 +1095,23 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.24" +version = "4.5.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7db6eca8c205649e8d3ccd05aa5042b1800a784e56bc7c43524fde8abbfa9b" +checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1255,9 +1254,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -1454,7 +1453,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1512,7 +1511,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1572,14 +1571,14 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1675,9 +1674,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fdeflate" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" dependencies = [ "simd-adler32", ] @@ -1713,9 +1712,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", @@ -1807,7 +1806,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1907,9 +1906,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1922,9 +1921,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1932,15 +1931,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1960,38 +1959,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -2167,9 +2166,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "gix-features" @@ -2219,9 +2218,9 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f924267408915fddcd558e3f37295cc7d6a3e50f8bd8b606cee0808c3915157e" +checksum = "6cae0e8661c3ff92688ce1c8b8058b3efb312aba9492bbe93661a21705ab431b" [[package]] name = "gl_generator" @@ -2242,15 +2241,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -2413,6 +2412,12 @@ dependencies = [ "serde", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "hashlink" version = "0.8.4" @@ -2564,7 +2569,7 @@ dependencies = [ "markup5ever 0.12.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2631,9 +2636,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -2708,21 +2713,21 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", "hyper 1.4.1", "hyper-util", - "rustls 0.23.12", + "rustls 0.23.14", "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", "tower-service", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", ] [[package]] @@ -2756,9 +2761,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", @@ -2769,16 +2774,15 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2818,15 +2822,15 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" dependencies = [ "crossbeam-deque", "globset", "log", "memchr", - "regex-automata 0.4.7", + "regex-automata 0.4.8", "same-file", "walkdir", "winapi-util", @@ -2852,12 +2856,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -2923,9 +2927,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is-terminal" @@ -3003,18 +3007,18 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] [[package]] name = "junction" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c9c415a9b7b1e86cd5738f39d34c9e78c765da7fb1756dbd7d31b3b0d2e7afa" +checksum = "72bbdfd737a243da3dfc1f99ee8d6e166480f17ab4ac84d7c34aacd73fc7bd16" dependencies = [ "scopeguard", "windows-sys 0.52.0", @@ -3071,9 +3075,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libdbus-sys" @@ -3166,7 +3170,7 @@ dependencies = [ "itertools 0.13.0", "linkcheck", "regex", - "reqwest 0.12.7", + "reqwest 0.12.8", "strum 0.26.3", "tokio", ] @@ -3385,9 +3389,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", "stable_deref_trait", @@ -3458,7 +3462,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", - "simd-adler32", ] [[package]] @@ -3468,6 +3471,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -3748,7 +3752,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3772,18 +3776,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" @@ -3826,7 +3830,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3939,9 +3943,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] name = "pbkdf2" @@ -3989,9 +3993,9 @@ source = "git+https://github.com/ankitects/rust-url.git?rev=bb930b8d089f4d30d7d1 [[package]] name = "pest" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -4000,9 +4004,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -4010,22 +4014,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "pest_meta" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", @@ -4111,7 +4115,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4134,22 +4138,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4166,9 +4170,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plist" @@ -4185,9 +4189,9 @@ dependencies = [ [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -4198,30 +4202,30 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "png" -version = "0.17.13" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.4", + "miniz_oxide 0.8.0", ] [[package]] @@ -4232,9 +4236,9 @@ checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "powerfmt" @@ -4270,7 +4274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4290,18 +4294,18 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" [[package]] name = "prost" @@ -4330,7 +4334,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.77", + "syn 2.0.79", "tempfile", ] @@ -4344,7 +4348,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4423,9 +4427,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831e8e819a138c36e212f3af3fd9eeffed6bf1510a805af35b0edee5ffa59433" +checksum = "00e89ce2565d6044ca31a3eb79a334c3a79a841120a98f64eea9f579564cb691" dependencies = [ "cfg-if", "indoc", @@ -4441,9 +4445,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8730e591b14492a8945cdff32f089250b05f5accecf74aeddf9e8272ce1fa8" +checksum = "d8afbaf3abd7325e08f35ffb8deb5892046fcb2608b703db6a583a5ba4cea01e" dependencies = [ "once_cell", "target-lexicon", @@ -4451,9 +4455,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e97e919d2df92eb88ca80a037969f44e5e70356559654962cbb3316d00300c6" +checksum = "ec15a5ba277339d04763f4c23d85987a5b08cbb494860be141e6a10a8eb88022" dependencies = [ "libc", "pyo3-build-config", @@ -4461,27 +4465,27 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb57983022ad41f9e683a599f2fd13c3664d7063a3ac5714cae4b7bee7d3f206" +checksum = "15e0f01b5364bcfbb686a52fc4181d412b708a68ed20c330db9fc8d2c2bf5a43" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "pyo3-macros-backend" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec480c0c51ddec81019531705acac51bcdbeae563557c982aa8263bb96880372" +checksum = "a09b550200e1e5ed9176976d0060cbc2ea82dc8515da07885e7b8153a85caacb" dependencies = [ "heck 0.5.0", "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4513,7 +4517,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.12", + "rustls 0.23.14", "socket2", "thiserror", "tokio", @@ -4530,7 +4534,7 @@ dependencies = [ "rand", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.12", + "rustls 0.23.14", "slab", "thiserror", "tinyvec", @@ -4697,9 +4701,9 @@ checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] @@ -4717,14 +4721,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -4738,13 +4742,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -4755,9 +4759,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "renderdoc-sys" @@ -4811,9 +4815,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", @@ -4823,7 +4827,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls 0.27.3", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -4836,9 +4840,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.12", + "rustls 0.23.14", "rustls-native-certs", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", @@ -4855,7 +4859,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", "windows-registry", ] @@ -4930,7 +4934,7 @@ dependencies = [ "clap", "flate2", "junction", - "reqwest 0.12.7", + "reqwest 0.12.8", "sha2", "tar", "termcolor", @@ -4975,9 +4979,9 @@ checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -5000,27 +5004,27 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "log", "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.7", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -5037,19 +5041,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -5063,9 +5066,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.7" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -5074,9 +5077,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -5096,9 +5099,9 @@ dependencies = [ [[package]] name = "safetensors" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7725d4d98fa515472f43a6e2bbf956c48e06b89bb50593a040e5945160214450" +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6" dependencies = [ "serde", "serde_json", @@ -5125,11 +5128,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5178,9 +5181,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -5215,9 +5218,9 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -5235,20 +5238,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -5274,7 +5277,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5430,23 +5433,23 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snafu" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b835cb902660db3415a672d862905e791e54d306c6e8189168c7f3d9ae1c79d" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" dependencies = [ "snafu-derive", ] [[package]] name = "snafu-derive" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d1e02fca405f6280643174a50c942219f0bbf4dbf7d480f1dd864d6f211ae5" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5558,7 +5561,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5571,7 +5574,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5593,9 +5596,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -5625,7 +5628,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5665,9 +5668,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", @@ -5699,9 +5702,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -5732,12 +5735,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" dependencies = [ "rustix", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -5753,22 +5756,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5891,7 +5894,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5920,7 +5923,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls 0.23.14", "rustls-pki-types", "tokio", ] @@ -5951,9 +5954,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -5979,9 +5982,9 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "toml_datetime", @@ -6011,14 +6014,14 @@ dependencies = [ [[package]] name = "tower" -version = "0.4.13" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper 0.1.2", "tokio", "tower-layer", "tower-service", @@ -6086,7 +6089,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6222,9 +6225,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unic-char-property" @@ -6286,7 +6289,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.77", + "syn 2.0.79", "unic-langid-impl", ] @@ -6322,42 +6325,42 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unindent" @@ -6387,12 +6390,12 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.23.12", + "rustls 0.23.14", "rustls-pki-types", "serde", "serde_json", "url", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", ] [[package]] @@ -6521,9 +6524,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -6532,24 +6535,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -6559,9 +6562,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6569,28 +6572,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" dependencies = [ "futures-util", "js-sys", @@ -6601,9 +6604,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -6627,9 +6630,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.5" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -6846,7 +6849,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6857,7 +6860,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -7049,9 +7052,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -7078,13 +7081,13 @@ dependencies = [ [[package]] name = "wiremock" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a59f8ae78a4737fb724f20106fb35ccb7cfe61ff335665d3042b3aa98e34717" +checksum = "7fff469918e7ca034884c7fd8f93fe27bacb7fcb599fd879df6c7b429a29b646" dependencies = [ "assert-json-diff", "async-trait", - "base64 0.21.7", + "base64 0.22.1", "deadpool", "futures", "http 1.1.0", @@ -7113,9 +7116,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" [[package]] name = "xml5ever" @@ -7166,7 +7169,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "synstructure", ] @@ -7188,7 +7191,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -7208,7 +7211,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index 78552be52..6d86959f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ ninja_gen = { "path" = "build/ninja_gen" } # pinned unicase = "=2.6.0" # any changes could invalidate sqlite indexes +utime = "=0.3.1" # marked as deprecated, but no native solution for folder mtimes exists # normal ammonia = "4.0.0" @@ -141,7 +142,6 @@ tugger-windows-codesign = "0.10.0" unic-langid = { version = "0.9.5", features = ["macros"] } unic-ucd-category = "0.9.0" unicode-normalization = "0.1.23" -utime = "0.3.1" walkdir = "2.5.0" which = "5.0.0" wiremock = "0.6.1" diff --git a/cargo/licenses.json b/cargo/licenses.json index eb75a72e7..911b0944c 100644 --- a/cargo/licenses.json +++ b/cargo/licenses.json @@ -1,7 +1,7 @@ [ { "name": "addr2line", - "version": "0.22.0", + "version": "0.24.2", "authors": null, "repository": "https://github.com/gimli-rs/addr2line", "license": "Apache-2.0 OR MIT", @@ -136,7 +136,7 @@ }, { "name": "anyhow", - "version": "1.0.86", + "version": "1.0.89", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/anyhow", "license": "Apache-2.0 OR MIT", @@ -145,7 +145,7 @@ }, { "name": "arrayref", - "version": "0.3.8", + "version": "0.3.9", "authors": "David Roundy ", "repository": "https://github.com/droundy/arrayref", "license": "BSD-2-Clause", @@ -181,7 +181,7 @@ }, { "name": "async-compression", - "version": "0.4.12", + "version": "0.4.15", "authors": "Wim Looman |Allen Bui ", "repository": "https://github.com/Nullus157/async-compression", "license": "Apache-2.0 OR MIT", @@ -190,7 +190,7 @@ }, { "name": "async-stream", - "version": "0.3.5", + "version": "0.3.6", "authors": "Carl Lerche ", "repository": "https://github.com/tokio-rs/async-stream", "license": "MIT", @@ -199,7 +199,7 @@ }, { "name": "async-stream-impl", - "version": "0.3.5", + "version": "0.3.6", "authors": "Carl Lerche ", "repository": "https://github.com/tokio-rs/async-stream", "license": "MIT", @@ -208,7 +208,7 @@ }, { "name": "async-trait", - "version": "0.1.82", + "version": "0.1.83", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/async-trait", "license": "Apache-2.0 OR MIT", @@ -226,7 +226,7 @@ }, { "name": "autocfg", - "version": "1.3.0", + "version": "1.4.0", "authors": "Josh Stone ", "repository": "https://github.com/cuviper/autocfg", "license": "Apache-2.0 OR MIT", @@ -235,7 +235,7 @@ }, { "name": "axum", - "version": "0.7.5", + "version": "0.7.7", "authors": null, "repository": "https://github.com/tokio-rs/axum", "license": "MIT", @@ -244,7 +244,7 @@ }, { "name": "axum-client-ip", - "version": "0.6.0", + "version": "0.6.1", "authors": null, "repository": "https://github.com/imbolc/axum-client-ip", "license": "MIT", @@ -253,7 +253,7 @@ }, { "name": "axum-core", - "version": "0.4.3", + "version": "0.4.5", "authors": null, "repository": "https://github.com/tokio-rs/axum", "license": "MIT", @@ -262,7 +262,7 @@ }, { "name": "axum-extra", - "version": "0.9.3", + "version": "0.9.4", "authors": null, "repository": "https://github.com/tokio-rs/axum", "license": "MIT", @@ -271,7 +271,7 @@ }, { "name": "axum-macros", - "version": "0.4.1", + "version": "0.4.2", "authors": null, "repository": "https://github.com/tokio-rs/axum", "license": "MIT", @@ -280,7 +280,7 @@ }, { "name": "backtrace", - "version": "0.3.73", + "version": "0.3.74", "authors": "The Rust Project Developers", "repository": "https://github.com/rust-lang/backtrace-rs", "license": "Apache-2.0 OR MIT", @@ -550,7 +550,7 @@ }, { "name": "bytemuck", - "version": "1.17.1", + "version": "1.19.0", "authors": "Lokathor ", "repository": "https://github.com/Lokathor/bytemuck", "license": "Apache-2.0 OR MIT OR Zlib", @@ -559,7 +559,7 @@ }, { "name": "bytemuck_derive", - "version": "1.7.1", + "version": "1.8.0", "authors": "Lokathor ", "repository": "https://github.com/Lokathor/bytemuck", "license": "Apache-2.0 OR MIT OR Zlib", @@ -577,7 +577,7 @@ }, { "name": "bytes", - "version": "1.7.1", + "version": "1.7.2", "authors": "Carl Lerche |Sean McArthur ", "repository": "https://github.com/tokio-rs/bytes", "license": "MIT", @@ -622,7 +622,7 @@ }, { "name": "cc", - "version": "1.1.15", + "version": "1.1.30", "authors": "Alex Crichton ", "repository": "https://github.com/rust-lang/cc-rs", "license": "Apache-2.0 OR MIT", @@ -775,7 +775,7 @@ }, { "name": "cpufeatures", - "version": "0.2.13", + "version": "0.2.14", "authors": "RustCrypto Developers", "repository": "https://github.com/RustCrypto/utils", "license": "Apache-2.0 OR MIT", @@ -1000,7 +1000,7 @@ }, { "name": "enum-as-inner", - "version": "0.6.0", + "version": "0.6.1", "authors": "Benjamin Fry ", "repository": "https://github.com/bluejekyll/enum-as-inner", "license": "Apache-2.0 OR MIT", @@ -1081,7 +1081,7 @@ }, { "name": "fdeflate", - "version": "0.3.4", + "version": "0.3.5", "authors": "The image-rs Developers", "repository": "https://github.com/image-rs/fdeflate", "license": "Apache-2.0 OR MIT", @@ -1099,7 +1099,7 @@ }, { "name": "flate2", - "version": "1.0.33", + "version": "1.0.34", "authors": "Alex Crichton |Josh Triplett ", "repository": "https://github.com/rust-lang/flate2-rs", "license": "Apache-2.0 OR MIT", @@ -1243,7 +1243,7 @@ }, { "name": "futures", - "version": "0.3.30", + "version": "0.3.31", "authors": null, "repository": "https://github.com/rust-lang/futures-rs", "license": "Apache-2.0 OR MIT", @@ -1252,7 +1252,7 @@ }, { "name": "futures-channel", - "version": "0.3.30", + "version": "0.3.31", "authors": null, "repository": "https://github.com/rust-lang/futures-rs", "license": "Apache-2.0 OR MIT", @@ -1261,7 +1261,7 @@ }, { "name": "futures-core", - "version": "0.3.30", + "version": "0.3.31", "authors": null, "repository": "https://github.com/rust-lang/futures-rs", "license": "Apache-2.0 OR MIT", @@ -1270,7 +1270,7 @@ }, { "name": "futures-executor", - "version": "0.3.30", + "version": "0.3.31", "authors": null, "repository": "https://github.com/rust-lang/futures-rs", "license": "Apache-2.0 OR MIT", @@ -1288,7 +1288,7 @@ }, { "name": "futures-io", - "version": "0.3.30", + "version": "0.3.31", "authors": null, "repository": "https://github.com/rust-lang/futures-rs", "license": "Apache-2.0 OR MIT", @@ -1297,7 +1297,7 @@ }, { "name": "futures-macro", - "version": "0.3.30", + "version": "0.3.31", "authors": null, "repository": "https://github.com/rust-lang/futures-rs", "license": "Apache-2.0 OR MIT", @@ -1306,7 +1306,7 @@ }, { "name": "futures-sink", - "version": "0.3.30", + "version": "0.3.31", "authors": null, "repository": "https://github.com/rust-lang/futures-rs", "license": "Apache-2.0 OR MIT", @@ -1315,7 +1315,7 @@ }, { "name": "futures-task", - "version": "0.3.30", + "version": "0.3.31", "authors": null, "repository": "https://github.com/rust-lang/futures-rs", "license": "Apache-2.0 OR MIT", @@ -1324,7 +1324,7 @@ }, { "name": "futures-util", - "version": "0.3.30", + "version": "0.3.31", "authors": null, "repository": "https://github.com/rust-lang/futures-rs", "license": "Apache-2.0 OR MIT", @@ -1432,7 +1432,7 @@ }, { "name": "gimli", - "version": "0.29.0", + "version": "0.31.1", "authors": null, "repository": "https://github.com/gimli-rs/gimli", "license": "Apache-2.0 OR MIT", @@ -1477,7 +1477,7 @@ }, { "name": "gix-trace", - "version": "0.1.9", + "version": "0.1.10", "authors": "Sebastian Thiel ", "repository": "https://github.com/Byron/gitoxide", "license": "Apache-2.0 OR MIT", @@ -1592,6 +1592,15 @@ "license_file": null, "description": "A Rust port of Google's SwissTable hash map" }, + { + "name": "hashbrown", + "version": "0.15.0", + "authors": "Amanieu d'Antras ", + "repository": "https://github.com/rust-lang/hashbrown", + "license": "Apache-2.0 OR MIT", + "license_file": null, + "description": "A Rust port of Google's SwissTable hash map" + }, { "name": "hashlink", "version": "0.8.4", @@ -1729,7 +1738,7 @@ }, { "name": "httparse", - "version": "1.9.4", + "version": "1.9.5", "authors": "Sean McArthur ", "repository": "https://github.com/seanmonstar/httparse", "license": "Apache-2.0 OR MIT", @@ -1756,7 +1765,7 @@ }, { "name": "hyper-rustls", - "version": "0.27.2", + "version": "0.27.3", "authors": null, "repository": "https://github.com/rustls/hyper-rustls", "license": "Apache-2.0 OR ISC OR MIT", @@ -1774,7 +1783,7 @@ }, { "name": "hyper-util", - "version": "0.1.7", + "version": "0.1.9", "authors": "Sean McArthur ", "repository": "https://github.com/hyperium/hyper-util", "license": "MIT", @@ -1783,7 +1792,7 @@ }, { "name": "iana-time-zone", - "version": "0.1.60", + "version": "0.1.61", "authors": "Andrew Straw |René Kijewski |Ryan Lopopolo ", "repository": "https://github.com/strawlab/iana-time-zone", "license": "Apache-2.0 OR MIT", @@ -1828,7 +1837,7 @@ }, { "name": "indexmap", - "version": "2.5.0", + "version": "2.6.0", "authors": null, "repository": "https://github.com/indexmap-rs/indexmap", "license": "Apache-2.0 OR MIT", @@ -1873,7 +1882,7 @@ }, { "name": "ipnet", - "version": "2.9.0", + "version": "2.10.1", "authors": "Kris Price ", "repository": "https://github.com/krisprice/ipnet", "license": "Apache-2.0 OR MIT", @@ -1936,7 +1945,7 @@ }, { "name": "js-sys", - "version": "0.3.70", + "version": "0.3.72", "authors": "The wasm-bindgen Developers", "repository": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/js-sys", "license": "Apache-2.0 OR MIT", @@ -1981,7 +1990,7 @@ }, { "name": "libc", - "version": "0.2.158", + "version": "0.2.159", "authors": "The Rust Project Developers", "repository": "https://github.com/rust-lang/libc", "license": "Apache-2.0 OR MIT", @@ -2152,7 +2161,7 @@ }, { "name": "memmap2", - "version": "0.9.4", + "version": "0.9.5", "authors": "Dan Burkert |Yevhenii Reizner ", "repository": "https://github.com/RazrFalcon/memmap2-rs", "license": "Apache-2.0 OR MIT", @@ -2413,7 +2422,7 @@ }, { "name": "object", - "version": "0.36.4", + "version": "0.36.5", "authors": null, "repository": "https://github.com/gimli-rs/object", "license": "Apache-2.0 OR MIT", @@ -2422,7 +2431,7 @@ }, { "name": "once_cell", - "version": "1.19.0", + "version": "1.20.2", "authors": "Aleksey Kladov ", "repository": "https://github.com/matklad/once_cell", "license": "Apache-2.0 OR MIT", @@ -2638,7 +2647,7 @@ }, { "name": "pin-project", - "version": "1.1.5", + "version": "1.1.6", "authors": null, "repository": "https://github.com/taiki-e/pin-project", "license": "Apache-2.0 OR MIT", @@ -2647,7 +2656,7 @@ }, { "name": "pin-project-internal", - "version": "1.1.5", + "version": "1.1.6", "authors": null, "repository": "https://github.com/taiki-e/pin-project", "license": "Apache-2.0 OR MIT", @@ -2674,7 +2683,7 @@ }, { "name": "pkg-config", - "version": "0.3.30", + "version": "0.3.31", "authors": "Alex Crichton ", "repository": "https://github.com/rust-lang/pkg-config-rs", "license": "Apache-2.0 OR MIT", @@ -2683,7 +2692,7 @@ }, { "name": "png", - "version": "0.17.13", + "version": "0.17.14", "authors": "The image-rs Developers", "repository": "https://github.com/image-rs/image-png", "license": "Apache-2.0 OR MIT", @@ -2764,7 +2773,7 @@ }, { "name": "proc-macro2", - "version": "1.0.86", + "version": "1.0.87", "authors": "David Tolnay |Alex Crichton ", "repository": "https://github.com/dtolnay/proc-macro2", "license": "Apache-2.0 OR MIT", @@ -2773,7 +2782,7 @@ }, { "name": "profiling", - "version": "1.0.15", + "version": "1.0.16", "authors": "Philip Degarmo ", "repository": "https://github.com/aclysma/profiling", "license": "Apache-2.0 OR MIT", @@ -3007,7 +3016,7 @@ }, { "name": "redox_syscall", - "version": "0.5.3", + "version": "0.5.7", "authors": "Jeremy Soller ", "repository": "https://gitlab.redox-os.org/redox-os/syscall", "license": "MIT", @@ -3025,7 +3034,7 @@ }, { "name": "regex", - "version": "1.10.6", + "version": "1.11.0", "authors": "The Rust Project Developers|Andrew Gallant ", "repository": "https://github.com/rust-lang/regex", "license": "Apache-2.0 OR MIT", @@ -3043,7 +3052,7 @@ }, { "name": "regex-automata", - "version": "0.4.7", + "version": "0.4.8", "authors": "The Rust Project Developers|Andrew Gallant ", "repository": "https://github.com/rust-lang/regex/tree/master/regex-automata", "license": "Apache-2.0 OR MIT", @@ -3061,7 +3070,7 @@ }, { "name": "regex-syntax", - "version": "0.8.4", + "version": "0.8.5", "authors": "The Rust Project Developers|Andrew Gallant ", "repository": "https://github.com/rust-lang/regex/tree/master/regex-syntax", "license": "Apache-2.0 OR MIT", @@ -3079,7 +3088,7 @@ }, { "name": "reqwest", - "version": "0.12.7", + "version": "0.12.8", "authors": "Sean McArthur ", "repository": "https://github.com/seanmonstar/reqwest", "license": "Apache-2.0 OR MIT", @@ -3151,7 +3160,7 @@ }, { "name": "rustix", - "version": "0.38.35", + "version": "0.38.37", "authors": "Dan Gohman |Jakub Konka ", "repository": "https://github.com/bytecodealliance/rustix", "license": "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT", @@ -3160,7 +3169,7 @@ }, { "name": "rustls", - "version": "0.23.12", + "version": "0.23.14", "authors": null, "repository": "https://github.com/rustls/rustls", "license": "Apache-2.0 OR ISC OR MIT", @@ -3169,7 +3178,7 @@ }, { "name": "rustls-native-certs", - "version": "0.7.3", + "version": "0.8.0", "authors": null, "repository": "https://github.com/rustls/rustls-native-certs", "license": "Apache-2.0 OR ISC OR MIT", @@ -3178,7 +3187,7 @@ }, { "name": "rustls-pemfile", - "version": "2.1.3", + "version": "2.2.0", "authors": null, "repository": "https://github.com/rustls/pemfile", "license": "Apache-2.0 OR ISC OR MIT", @@ -3187,7 +3196,7 @@ }, { "name": "rustls-pki-types", - "version": "1.8.0", + "version": "1.10.0", "authors": null, "repository": "https://github.com/rustls/pki-types", "license": "Apache-2.0 OR MIT", @@ -3196,7 +3205,7 @@ }, { "name": "rustls-webpki", - "version": "0.102.7", + "version": "0.102.8", "authors": null, "repository": "https://github.com/rustls/webpki", "license": "ISC", @@ -3205,7 +3214,7 @@ }, { "name": "rustversion", - "version": "1.0.17", + "version": "1.0.18", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/rustversion", "license": "Apache-2.0 OR MIT", @@ -3232,7 +3241,7 @@ }, { "name": "safetensors", - "version": "0.4.4", + "version": "0.4.5", "authors": null, "repository": "https://github.com/huggingface/safetensors", "license": "Apache-2.0", @@ -3259,7 +3268,7 @@ }, { "name": "schannel", - "version": "0.1.23", + "version": "0.1.26", "authors": "Steven Fackler |Steffen Butzer ", "repository": "https://github.com/steffengy/schannel-rs", "license": "MIT", @@ -3295,7 +3304,7 @@ }, { "name": "security-framework-sys", - "version": "2.11.1", + "version": "2.12.0", "authors": "Steven Fackler |Kornel ", "repository": "https://github.com/kornelski/rust-security-framework", "license": "Apache-2.0 OR MIT", @@ -3331,7 +3340,7 @@ }, { "name": "serde", - "version": "1.0.209", + "version": "1.0.210", "authors": "Erick Tryzelaar |David Tolnay ", "repository": "https://github.com/serde-rs/serde", "license": "Apache-2.0 OR MIT", @@ -3349,7 +3358,7 @@ }, { "name": "serde_derive", - "version": "1.0.209", + "version": "1.0.210", "authors": "Erick Tryzelaar |David Tolnay ", "repository": "https://github.com/serde-rs/serde", "license": "Apache-2.0 OR MIT", @@ -3358,7 +3367,7 @@ }, { "name": "serde_json", - "version": "1.0.127", + "version": "1.0.128", "authors": "Erick Tryzelaar |David Tolnay ", "repository": "https://github.com/serde-rs/json", "license": "Apache-2.0 OR MIT", @@ -3520,7 +3529,7 @@ }, { "name": "snafu", - "version": "0.8.4", + "version": "0.8.5", "authors": "Jake Goulding ", "repository": "https://github.com/shepmaster/snafu", "license": "Apache-2.0 OR MIT", @@ -3529,7 +3538,7 @@ }, { "name": "snafu-derive", - "version": "0.8.4", + "version": "0.8.5", "authors": "Jake Goulding ", "repository": "https://github.com/shepmaster/snafu", "license": "Apache-2.0 OR MIT", @@ -3664,7 +3673,7 @@ }, { "name": "syn", - "version": "2.0.77", + "version": "2.0.79", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/syn", "license": "Apache-2.0 OR MIT", @@ -3718,7 +3727,7 @@ }, { "name": "tempfile", - "version": "3.12.0", + "version": "3.13.0", "authors": "Steven Allen |The Rust Project Developers|Ashley Mannix |Jason White ", "repository": "https://github.com/Stebalien/tempfile", "license": "Apache-2.0 OR MIT", @@ -3754,7 +3763,7 @@ }, { "name": "thiserror", - "version": "1.0.63", + "version": "1.0.64", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/thiserror", "license": "Apache-2.0 OR MIT", @@ -3763,7 +3772,7 @@ }, { "name": "thiserror-impl", - "version": "1.0.63", + "version": "1.0.64", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/thiserror", "license": "Apache-2.0 OR MIT", @@ -3898,7 +3907,7 @@ }, { "name": "tokio-util", - "version": "0.7.11", + "version": "0.7.12", "authors": "Tokio Contributors ", "repository": "https://github.com/tokio-rs/tokio", "license": "MIT", @@ -3916,7 +3925,7 @@ }, { "name": "toml_edit", - "version": "0.22.20", + "version": "0.22.22", "authors": "Andronik Ordian |Ed Page ", "repository": "https://github.com/toml-rs/toml", "license": "Apache-2.0 OR MIT", @@ -3934,7 +3943,7 @@ }, { "name": "tower", - "version": "0.4.13", + "version": "0.5.1", "authors": "Tower Maintainers ", "repository": "https://github.com/tower-rs/tower", "license": "MIT", @@ -4141,7 +4150,7 @@ }, { "name": "unicode-bidi", - "version": "0.3.15", + "version": "0.3.17", "authors": "The Servo Project Developers", "repository": "https://github.com/servo/unicode-bidi", "license": "Apache-2.0 OR MIT", @@ -4150,7 +4159,7 @@ }, { "name": "unicode-ident", - "version": "1.0.12", + "version": "1.0.13", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/unicode-ident", "license": "(MIT OR Apache-2.0) AND Unicode-DFS-2016", @@ -4159,7 +4168,7 @@ }, { "name": "unicode-normalization", - "version": "0.1.23", + "version": "0.1.24", "authors": "kwantam |Manish Goregaokar ", "repository": "https://github.com/unicode-rs/unicode-normalization", "license": "Apache-2.0 OR MIT", @@ -4168,7 +4177,7 @@ }, { "name": "unicode-segmentation", - "version": "1.11.0", + "version": "1.12.0", "authors": "kwantam |Manish Goregaokar ", "repository": "https://github.com/unicode-rs/unicode-segmentation", "license": "Apache-2.0 OR MIT", @@ -4177,7 +4186,7 @@ }, { "name": "unicode-width", - "version": "0.1.13", + "version": "0.1.14", "authors": "kwantam |Manish Goregaokar ", "repository": "https://github.com/unicode-rs/unicode-width", "license": "Apache-2.0 OR MIT", @@ -4186,7 +4195,7 @@ }, { "name": "unicode-xid", - "version": "0.2.5", + "version": "0.2.6", "authors": "erick.tryzelaar |kwantam |Manish Goregaokar ", "repository": "https://github.com/unicode-rs/unicode-xid", "license": "Apache-2.0 OR MIT", @@ -4312,7 +4321,7 @@ }, { "name": "wasm-bindgen", - "version": "0.2.93", + "version": "0.2.95", "authors": "The wasm-bindgen Developers", "repository": "https://github.com/rustwasm/wasm-bindgen", "license": "Apache-2.0 OR MIT", @@ -4321,7 +4330,7 @@ }, { "name": "wasm-bindgen-backend", - "version": "0.2.93", + "version": "0.2.95", "authors": "The wasm-bindgen Developers", "repository": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/backend", "license": "Apache-2.0 OR MIT", @@ -4330,7 +4339,7 @@ }, { "name": "wasm-bindgen-futures", - "version": "0.4.43", + "version": "0.4.45", "authors": "The wasm-bindgen Developers", "repository": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/futures", "license": "Apache-2.0 OR MIT", @@ -4339,7 +4348,7 @@ }, { "name": "wasm-bindgen-macro", - "version": "0.2.93", + "version": "0.2.95", "authors": "The wasm-bindgen Developers", "repository": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro", "license": "Apache-2.0 OR MIT", @@ -4348,7 +4357,7 @@ }, { "name": "wasm-bindgen-macro-support", - "version": "0.2.93", + "version": "0.2.95", "authors": "The wasm-bindgen Developers", "repository": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support", "license": "Apache-2.0 OR MIT", @@ -4357,7 +4366,7 @@ }, { "name": "wasm-bindgen-shared", - "version": "0.2.93", + "version": "0.2.95", "authors": "The wasm-bindgen Developers", "repository": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared", "license": "Apache-2.0 OR MIT", @@ -4366,7 +4375,7 @@ }, { "name": "wasm-streams", - "version": "0.4.0", + "version": "0.4.1", "authors": "Mattias Buelens ", "repository": "https://github.com/MattiasBuelens/wasm-streams/", "license": "Apache-2.0 OR MIT", @@ -4375,7 +4384,7 @@ }, { "name": "web-sys", - "version": "0.3.70", + "version": "0.3.72", "authors": "The wasm-bindgen Developers", "repository": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/web-sys", "license": "Apache-2.0 OR MIT", @@ -4393,7 +4402,7 @@ }, { "name": "webpki-roots", - "version": "0.26.5", + "version": "0.26.6", "authors": null, "repository": "https://github.com/rustls/webpki-roots", "license": "MPL-2.0", @@ -4762,7 +4771,7 @@ }, { "name": "winnow", - "version": "0.6.18", + "version": "0.6.20", "authors": null, "repository": "https://github.com/winnow-rs/winnow", "license": "MIT", @@ -4771,7 +4780,7 @@ }, { "name": "wiremock", - "version": "0.6.1", + "version": "0.6.2", "authors": "Luca Palmieri ", "repository": "https://github.com/LukeMathWalker/wiremock-rs", "license": "Apache-2.0 OR MIT", @@ -4780,7 +4789,7 @@ }, { "name": "xml-rs", - "version": "0.8.21", + "version": "0.8.22", "authors": "Vladimir Matveev ", "repository": "https://github.com/kornelski/xml-rs", "license": "MIT", diff --git a/rslib/src/sync/media/database/client/changetracker.rs b/rslib/src/sync/media/database/client/changetracker.rs index 5e34d324f..7f9b3f3cd 100644 --- a/rslib/src/sync/media/database/client/changetracker.rs +++ b/rslib/src/sync/media/database/client/changetracker.rs @@ -261,6 +261,8 @@ mod test { .duration_since(time::UNIX_EPOCH) .unwrap() .as_secs() as i64; + // we rely on an external crate, as Rust's File::set_times() does not work + // on directories utime::set_file_times(p, secs, secs).unwrap(); } From 723b5e9bcc1c6253db6746418463b9d75c8cf531 Mon Sep 17 00:00:00 2001 From: Han Yeong-woo Date: Tue, 15 Oct 2024 23:31:17 +0900 Subject: [PATCH 005/113] Fully switch to File::set_times() from utime crate (#3501) * Fully switch to File::set_times() from utime crate * Switch to open_file() (dae) Future me will end up wondering why we're explicitly declaring read=true --- Cargo.lock | 11 ----------- Cargo.toml | 1 - cargo/licenses.json | 9 --------- rslib/Cargo.toml | 1 - rslib/io/src/lib.rs | 5 ++--- .../src/sync/media/database/client/changetracker.rs | 13 ++++++------- 6 files changed, 8 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea3c70c7a..38bcdd6f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,7 +171,6 @@ dependencies = [ "unic-ucd-category", "unicase", "unicode-normalization", - "utime", "windows 0.56.0", "wiremock", "zip", @@ -6422,16 +6421,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "utime" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91baa0c65eabd12fcbdac8cc35ff16159cab95cae96d0222d6d0271db6193cef" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "uuid" version = "1.10.0" diff --git a/Cargo.toml b/Cargo.toml index 6d86959f0..8d3c0052b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,6 @@ ninja_gen = { "path" = "build/ninja_gen" } # pinned unicase = "=2.6.0" # any changes could invalidate sqlite indexes -utime = "=0.3.1" # marked as deprecated, but no native solution for folder mtimes exists # normal ammonia = "4.0.0" diff --git a/cargo/licenses.json b/cargo/licenses.json index 911b0944c..83bbcf653 100644 --- a/cargo/licenses.json +++ b/cargo/licenses.json @@ -4238,15 +4238,6 @@ "license_file": null, "description": "Incremental, zero-copy UTF-8 decoding with error handling" }, - { - "name": "utime", - "version": "0.3.1", - "authors": "Hyeon Kim ", - "repository": "https://github.com/simnalamburt/utime", - "license": "Apache-2.0 OR MIT", - "license_file": null, - "description": "A missing utime function for Rust." - }, { "name": "uuid", "version": "1.10.0", diff --git a/rslib/Cargo.toml b/rslib/Cargo.toml index fb14826b4..1c4abf46f 100644 --- a/rslib/Cargo.toml +++ b/rslib/Cargo.toml @@ -103,7 +103,6 @@ tracing-subscriber.workspace = true unic-ucd-category.workspace = true unicase.workspace = true unicode-normalization.workspace = true -utime.workspace = true zip.workspace = true zstd.workspace = true diff --git a/rslib/io/src/lib.rs b/rslib/io/src/lib.rs index f9ee9758a..c6a6a0c51 100644 --- a/rslib/io/src/lib.rs +++ b/rslib/io/src/lib.rs @@ -53,10 +53,9 @@ pub fn write_file(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result< op: FileOp::Write, }) } -/// See [File::set_times]. Note that this won't work on folders. +/// See [File::set_times]. pub fn set_file_times(path: impl AsRef, times: FileTimes) -> Result<()> { - let file = open_file_ext(&path, OpenOptions::new().write(true).to_owned())?; - file.set_times(times).context(FileIoSnafu { + open_file(&path)?.set_times(times).context(FileIoSnafu { path: path.as_ref(), op: FileOp::SetFileTimes, }) diff --git a/rslib/src/sync/media/database/client/changetracker.rs b/rslib/src/sync/media/database/client/changetracker.rs index 7f9b3f3cd..2d2220c7c 100644 --- a/rslib/src/sync/media/database/client/changetracker.rs +++ b/rslib/src/sync/media/database/client/changetracker.rs @@ -239,11 +239,13 @@ where #[cfg(test)] mod test { use std::fs; + use std::fs::FileTimes; use std::path::Path; use std::time; use std::time::Duration; use anki_io::create_dir; + use anki_io::set_file_times; use anki_io::write_file; use tempfile::tempdir; @@ -257,13 +259,10 @@ mod test { fn change_mtime(p: &Path) { let mtime = p.metadata().unwrap().modified().unwrap(); let new_mtime = mtime - Duration::from_secs(3); - let secs = new_mtime - .duration_since(time::UNIX_EPOCH) - .unwrap() - .as_secs() as i64; - // we rely on an external crate, as Rust's File::set_times() does not work - // on directories - utime::set_file_times(p, secs, secs).unwrap(); + let times = FileTimes::new() + .set_accessed(new_mtime) + .set_modified(new_mtime); + set_file_times(p, times).unwrap(); } #[test] From f3ca4646fcd7764d9ec6386f98de4fa0c1c24ccd Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Wed, 16 Oct 2024 00:35:26 +1000 Subject: [PATCH 006/113] Revert "Fully switch to File::set_times() from utime crate (#3501)" (#3502) This reverts commit 723b5e9bcc1c6253db6746418463b9d75c8cf531. --- Cargo.lock | 11 +++++++++++ Cargo.toml | 1 + cargo/licenses.json | 9 +++++++++ rslib/Cargo.toml | 1 + rslib/io/src/lib.rs | 5 +++-- .../src/sync/media/database/client/changetracker.rs | 13 +++++++------ 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38bcdd6f6..ea3c70c7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,6 +171,7 @@ dependencies = [ "unic-ucd-category", "unicase", "unicode-normalization", + "utime", "windows 0.56.0", "wiremock", "zip", @@ -6421,6 +6422,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "utime" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91baa0c65eabd12fcbdac8cc35ff16159cab95cae96d0222d6d0271db6193cef" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "uuid" version = "1.10.0" diff --git a/Cargo.toml b/Cargo.toml index 8d3c0052b..6d86959f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ ninja_gen = { "path" = "build/ninja_gen" } # pinned unicase = "=2.6.0" # any changes could invalidate sqlite indexes +utime = "=0.3.1" # marked as deprecated, but no native solution for folder mtimes exists # normal ammonia = "4.0.0" diff --git a/cargo/licenses.json b/cargo/licenses.json index 83bbcf653..911b0944c 100644 --- a/cargo/licenses.json +++ b/cargo/licenses.json @@ -4238,6 +4238,15 @@ "license_file": null, "description": "Incremental, zero-copy UTF-8 decoding with error handling" }, + { + "name": "utime", + "version": "0.3.1", + "authors": "Hyeon Kim ", + "repository": "https://github.com/simnalamburt/utime", + "license": "Apache-2.0 OR MIT", + "license_file": null, + "description": "A missing utime function for Rust." + }, { "name": "uuid", "version": "1.10.0", diff --git a/rslib/Cargo.toml b/rslib/Cargo.toml index 1c4abf46f..fb14826b4 100644 --- a/rslib/Cargo.toml +++ b/rslib/Cargo.toml @@ -103,6 +103,7 @@ tracing-subscriber.workspace = true unic-ucd-category.workspace = true unicase.workspace = true unicode-normalization.workspace = true +utime.workspace = true zip.workspace = true zstd.workspace = true diff --git a/rslib/io/src/lib.rs b/rslib/io/src/lib.rs index c6a6a0c51..f9ee9758a 100644 --- a/rslib/io/src/lib.rs +++ b/rslib/io/src/lib.rs @@ -53,9 +53,10 @@ pub fn write_file(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result< op: FileOp::Write, }) } -/// See [File::set_times]. +/// See [File::set_times]. Note that this won't work on folders. pub fn set_file_times(path: impl AsRef, times: FileTimes) -> Result<()> { - open_file(&path)?.set_times(times).context(FileIoSnafu { + let file = open_file_ext(&path, OpenOptions::new().write(true).to_owned())?; + file.set_times(times).context(FileIoSnafu { path: path.as_ref(), op: FileOp::SetFileTimes, }) diff --git a/rslib/src/sync/media/database/client/changetracker.rs b/rslib/src/sync/media/database/client/changetracker.rs index 2d2220c7c..7f9b3f3cd 100644 --- a/rslib/src/sync/media/database/client/changetracker.rs +++ b/rslib/src/sync/media/database/client/changetracker.rs @@ -239,13 +239,11 @@ where #[cfg(test)] mod test { use std::fs; - use std::fs::FileTimes; use std::path::Path; use std::time; use std::time::Duration; use anki_io::create_dir; - use anki_io::set_file_times; use anki_io::write_file; use tempfile::tempdir; @@ -259,10 +257,13 @@ mod test { fn change_mtime(p: &Path) { let mtime = p.metadata().unwrap().modified().unwrap(); let new_mtime = mtime - Duration::from_secs(3); - let times = FileTimes::new() - .set_accessed(new_mtime) - .set_modified(new_mtime); - set_file_times(p, times).unwrap(); + let secs = new_mtime + .duration_since(time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + // we rely on an external crate, as Rust's File::set_times() does not work + // on directories + utime::set_file_times(p, secs, secs).unwrap(); } #[test] From 8f4cab6a1ae0fe61234cd0de751880f39dcf437f Mon Sep 17 00:00:00 2001 From: Cy Pokhrel Date: Tue, 15 Oct 2024 14:38:35 +0000 Subject: [PATCH 007/113] Fix editor loses focus when toggling list if list item empty (#3483) * fix editor loses focus when toggling list if list item empty * fix CONTRIBUTORS --- CONTRIBUTORS | 2 +- ts/editor/editor-toolbar/CommandIconButton.svelte | 1 + ts/editor/rich-text-input/RichTextInput.svelte | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b0002241c..a4b1aefb1 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -194,7 +194,7 @@ Gregory Abrasaldo Taylor Obyen <162023405+taylorobyen@users.noreply.github.com> Kris Cherven twwn -Shirish Pokhrel +Cy Pokhrel Park Hyunwoo Tomas Fabrizio Orsi diff --git a/ts/editor/editor-toolbar/CommandIconButton.svelte b/ts/editor/editor-toolbar/CommandIconButton.svelte index e81d8a793..83f4a9a93 100644 --- a/ts/editor/editor-toolbar/CommandIconButton.svelte +++ b/ts/editor/editor-toolbar/CommandIconButton.svelte @@ -27,6 +27,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html function action() { execCommand(key); + $focusedInput?.focus(); } $: disabled = !$focusedInput || !editingInputIsRichText($focusedInput); diff --git a/ts/editor/rich-text-input/RichTextInput.svelte b/ts/editor/rich-text-input/RichTextInput.svelte index bf9656fc1..74abed4e9 100644 --- a/ts/editor/rich-text-input/RichTextInput.svelte +++ b/ts/editor/rich-text-input/RichTextInput.svelte @@ -117,6 +117,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html async function focus(): Promise { const richText = await richTextPromise; + richText.blur(); richText.focus(); } From 694a5089a9ed7c5aa14f92e4f7879d2b49fd61f7 Mon Sep 17 00:00:00 2001 From: "Hikaru Y." Date: Tue, 15 Oct 2024 23:47:33 +0900 Subject: [PATCH 008/113] Fix 'Discard changes' dialog appearing even when no changes are made (#3495) * Fix 'Discard changes' dialog appearing even when no changes are made https://forums.ankiweb.net/t/anki-24-10-beta/49989/166 * Fix geometry of deck options window not being saved evt.accept() does not seem to trigger reject(). --- qt/aqt/deckoptions.py | 3 +- ts/routes/deck-options/[deckId]/+page.svelte | 3 +- ts/routes/deck-options/lib.ts | 50 ++++++++------------ 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/qt/aqt/deckoptions.py b/qt/aqt/deckoptions.py index e4802f98a..e725ddc4a 100644 --- a/qt/aqt/deckoptions.py +++ b/qt/aqt/deckoptions.py @@ -69,8 +69,7 @@ class DeckOptionsDialog(QDialog): def closeEvent(self, evt: QCloseEvent) -> None: if self._close_event_has_cleaned_up: - evt.accept() - return + return super().closeEvent(evt) evt.ignore() self.check_pending_changes() diff --git a/ts/routes/deck-options/[deckId]/+page.svelte b/ts/routes/deck-options/[deckId]/+page.svelte index ec99facc1..c5064a950 100644 --- a/ts/routes/deck-options/[deckId]/+page.svelte +++ b/ts/routes/deck-options/[deckId]/+page.svelte @@ -16,7 +16,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html globalThis.anki.deckOptionsPendingChanges = async (): Promise => { await commitEditing(); if (bridgeCommandsAvailable()) { - if (data.state.isModified()) { + if (await data.state.isModified()) { bridgeCommand("confirmDiscardChanges"); } else { bridgeCommand("_close"); @@ -28,6 +28,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html globalThis.$deckOptions = new Promise((resolve, _reject) => { resolve(page); }); + data.state.resolveOriginalConfigs(); if (bridgeCommandsAvailable()) { bridgeCommand("deckOptionsReady"); } diff --git a/ts/routes/deck-options/lib.ts b/ts/routes/deck-options/lib.ts index 04f48793b..0c57f2977 100644 --- a/ts/routes/deck-options/lib.ts +++ b/ts/routes/deck-options/lib.ts @@ -11,7 +11,8 @@ import type { import { DeckConfig, DeckConfig_Config, DeckConfigsForUpdate_CurrentDeck_Limits } from "@generated/anki/deck_config_pb"; import { updateDeckConfigs } from "@generated/backend"; import { localeCompare } from "@tslib/i18n"; -import { cloneDeep, isEqual, pickBy } from "lodash-es"; +import { promiseWithResolver } from "@tslib/promise"; +import { cloneDeep, isEqual } from "lodash-es"; import { tick } from "svelte"; import type { Readable, Writable } from "svelte/store"; import { get, readable, writable } from "svelte/store"; @@ -33,7 +34,7 @@ export interface ConfigListEntry { current: boolean; } -type Configs = +type AllConfigs = & Required< Pick< PlainMessage, @@ -48,10 +49,6 @@ type Configs = > & { currentConfig: DeckConfig_Config }; -type DeepPartial = { - [key in keyof T]: key extends K ? Partial : T[key]; -}; - export class DeckOptionsState { readonly currentConfig: Writable; readonly currentAuxData: Writable>; @@ -68,7 +65,8 @@ export class DeckOptionsState { readonly daysSinceLastOptimization: Writable; readonly currentPresetName: Writable; /** Used to detect if there are any pending changes */ - readonly originalConfigs: Configs; + readonly originalConfigsPromise: Promise; + readonly originalConfigsResolve: (value: AllConfigs) => void; private targetDeckId: DeckOptionsId; private configs: ConfigWithCount[]; @@ -124,16 +122,9 @@ export class DeckOptionsState { this.currentConfig.subscribe((val) => this.onCurrentConfigChanged(val)); this.currentAuxData.subscribe((val) => this.onCurrentAuxDataChanged(val)); - this.originalConfigs = cloneDeep({ - configs: this.configs.map(c => c.config!), - cardStateCustomizer: data.cardStateCustomizer, - limits: get(this.deckLimits), - newCardsIgnoreReviewLimit: data.newCardsIgnoreReviewLimit, - applyAllParentLimits: data.applyAllParentLimits, - fsrs: data.fsrs, - fsrsReschedule: get(this.fsrsReschedule), - currentConfig: get(this.currentConfig), - }); + // Must be resolved after all components are mounted, as some components + // may modify the config during their initialization. + [this.originalConfigsPromise, this.originalConfigsResolve] = promiseWithResolver(); } setCurrentIndex(index: number): void { @@ -326,24 +317,28 @@ export class DeckOptionsState { return list; } - isModified(): boolean { - const original: DeepPartial = { - ...this.originalConfigs, - limits: omitUndefined(this.originalConfigs.limits), - }; - const current: typeof original = { + private getAllConfigs(): AllConfigs { + return cloneDeep({ configs: this.configs.map(c => c.config), cardStateCustomizer: get(this.cardStateCustomizer), - limits: omitUndefined(get(this.deckLimits)), + limits: get(this.deckLimits), newCardsIgnoreReviewLimit: get(this.newCardsIgnoreReviewLimit), applyAllParentLimits: get(this.applyAllParentLimits), fsrs: get(this.fsrs), fsrsReschedule: get(this.fsrsReschedule), currentConfig: get(this.currentConfig), - }; + }); + } + async isModified(): Promise { + const original = await this.originalConfigsPromise; + const current = this.getAllConfigs(); return !isEqual(original, current); } + + resolveOriginalConfigs(): void { + this.originalConfigsResolve(this.getAllConfigs()); + } } function bytesToObject(bytes: Uint8Array): Record { @@ -413,11 +408,6 @@ export class ValueTab { } } -/** Returns a copy of the given object with the properties whose values are 'undefined' omitted */ -function omitUndefined(obj: T): Partial { - return pickBy(obj, val => val !== undefined); -} - /** Ensure blur handler has fired so changes get committed. */ export async function commitEditing(): Promise { if (document.activeElement instanceof HTMLElement) { From a537d349b8e8166f3edfebbf9d6c806d053bd124 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Tue, 15 Oct 2024 08:08:24 -0700 Subject: [PATCH 009/113] Enable strict_optional for aqt/editor.py (#3500) * Enable strict_optional for aqt/editor.py * Fix mypy errors in EditorWebView class * Fix mypy errors in Editor class * DRY * Match same short circuiting behavior * Convention --- .mypy.ini | 2 + qt/aqt/editor.py | 150 +++++++++++++++++++++++++++++++---------------- 2 files changed, 101 insertions(+), 51 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index f9fdf42f5..5d6d2be5c 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -38,6 +38,8 @@ strict_optional = True strict_optional = True [mypy-aqt.operations.*] strict_optional = True +[mypy-aqt.editor] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 4f64c5f2f..4c2cdaf23 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -34,7 +34,7 @@ from anki.collection import Config, SearchNode from anki.consts import MODEL_CLOZE from anki.hooks import runFilter from anki.httpclient import HttpClient -from anki.models import NotetypeId, StockNotetype +from anki.models import NotetypeDict, NotetypeId, StockNotetype from anki.notes import Note, NoteFieldsCheckResult, NoteId from anki.utils import checksum, is_lin, is_mac, is_win, namedtmp from aqt import AnkiQt, colors, gui_hooks @@ -242,38 +242,35 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too rightside: bool = True, ) -> str: """Assign func to bridge cmd, register shortcut, return button""" - if func: - def wrapped_func(editor: Editor) -> None: - self.call_after_note_saved( - functools.partial(func, editor), keepFocus=True - ) + def wrapped_func(editor: Editor) -> None: + self.call_after_note_saved(functools.partial(func, editor), keepFocus=True) - self._links[cmd] = wrapped_func + self._links[cmd] = wrapped_func - if keys: + if keys: - def on_activated() -> None: - wrapped_func(self) + def on_activated() -> None: + wrapped_func(self) - if toggleable: - # generate a random id for triggering toggle - id = id or str(randrange(1_000_000)) + if toggleable: + # generate a random id for triggering toggle + id = id or str(randrange(1_000_000)) - def on_hotkey() -> None: - on_activated() - self.web.eval( - f'toggleEditorButton(document.getElementById("{id}"));' - ) + def on_hotkey() -> None: + on_activated() + self.web.eval( + f'toggleEditorButton(document.getElementById("{id}"));' + ) - else: - on_hotkey = on_activated + else: + on_hotkey = on_activated - QShortcut( # type: ignore - QKeySequence(keys), - self.widget, - activated=on_hotkey, - ) + QShortcut( # type: ignore + QKeySequence(keys), + self.widget, + activated=on_hotkey, + ) btn = self._addButton( icon, @@ -363,7 +360,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too def _onFields(self) -> None: from aqt.fields import FieldDialog - FieldDialog(self.mw, self.note.note_type(), parent=self.parentWindow) + FieldDialog(self.mw, self.note_type(), parent=self.parentWindow) def onCardLayout(self) -> None: self.call_after_note_saved(self._onCardLayout) @@ -375,6 +372,8 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too ord = self.card.ord else: ord = 0 + + assert self.note is not None CardLayout( self.mw, self.note, @@ -435,7 +434,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too gui_hooks.editor_did_focus_field(self.note, self.currentField) elif cmd.startswith("toggleStickyAll"): - model = self.note.note_type() + model = self.note_type() flds = model["flds"] any_sticky = any([fld["sticky"] for fld in flds]) @@ -456,7 +455,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too (type, num) = cmd.split(":", 1) ord = int(num) - model = self.note.note_type() + model = self.note_type() fld = model["flds"][ord] new_state = not fld["sticky"] fld["sticky"] = new_state @@ -469,10 +468,12 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too elif cmd.startswith("lastTextColor"): (_, textColor) = cmd.split(":", 1) + assert self.mw.pm.profile is not None self.mw.pm.profile["lastTextColor"] = textColor elif cmd.startswith("lastHighlightColor"): (_, highlightColor) = cmd.split(":", 1) + assert self.mw.pm.profile is not None self.mw.pm.profile["lastHighlightColor"] = highlightColor elif cmd.startswith("saveTags"): @@ -545,11 +546,12 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too for fld, val in self.note.items() ] - flds = self.note.note_type()["flds"] + note_type = self.note_type() + flds = note_type["flds"] collapsed = [fld["collapsed"] for fld in flds] plain_texts = [fld.get("plainText", False) for fld in flds] descriptions = [fld.get("description", "") for fld in flds] - notetype_meta = {"id": self.note.mid, "modTime": self.note.note_type()["mod"]} + notetype_meta = {"id": self.note.mid, "modTime": note_type["mod"]} self.widget.show() @@ -566,6 +568,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too self.web.setFocus() gui_hooks.editor_did_load_note(self) + assert self.mw.pm.profile is not None text_color = self.mw.pm.profile.get("lastTextColor", "#0000ff") highlight_color = self.mw.pm.profile.get("lastHighlightColor", "#0000ff") @@ -590,7 +593,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too """ if self.addMode: - sticky = [field["sticky"] for field in self.note.note_type()["flds"]] + sticky = [field["sticky"] for field in self.note_type()["flds"]] js += " setSticky(%s);" % json.dumps(sticky) if ( @@ -607,6 +610,9 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too def _save_current_note(self) -> None: "Call after note is updated with data from webview." + if not self.note: + return + update_note(parent=self.widget, note=self.note).run_in_background( initiator=self ) @@ -614,7 +620,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too def fonts(self) -> list[tuple[str, int, bool]]: return [ (gui_hooks.editor_will_use_font_for_field(f["font"]), f["size"], f["rtl"]) - for f in self.note.note_type()["flds"] + for f in self.note_type()["flds"] ] def call_after_note_saved( @@ -648,6 +654,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too checkValid = _check_and_update_duplicate_display_async def _update_duplicate_display(self, result: NoteFieldsCheckResult.V) -> None: + assert self.note is not None cols = [""] * len(self.note.fields) cloze_hint = "" if result == NoteFieldsCheckResult.DUPLICATE: @@ -665,13 +672,14 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too ) def showDupes(self) -> None: + assert self.note is not None aqt.dialogs.open( "Browser", self.mw, search=( SearchNode( dupe=SearchNode.Dupe( - notetype_id=self.note.note_type()["id"], + notetype_id=self.note_type()["id"], first_field=self.note.fields[0], ) ), @@ -681,7 +689,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too def fieldsAreBlank(self, previousNote: Note | None = None) -> bool: if not self.note: return True - m = self.note.note_type() + m = self.note_type() for c, f in enumerate(self.note.fields): f = f.replace("
", "").strip() notChangedvalues = {"", "
"} @@ -696,7 +704,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too # prevent any remaining evalWithCallback() events from firing after C++ object deleted if self.web: self.web.cleanup() - self.web = None + self.web = None # type: ignore # legacy @@ -729,9 +737,11 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too if self.tags.col != self.mw.col: self.tags.setCol(self.mw.col) if not self.tags.text() or not self.addMode: + assert self.note is not None self.tags.setText(self.note.string_tags().strip()) def on_tag_focus_lost(self) -> None: + assert self.note is not None self.note.tags = self.mw.col.tags.split(self.tags.text()) gui_hooks.editor_did_update_tags(self.note) if not self.addMode: @@ -826,7 +836,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too # Media downloads ###################################################################### - def urlToLink(self, url: str) -> str | None: + def urlToLink(self, url: str) -> str: fname = self.urlToFile(url) if not fname: return '{}'.format( @@ -1037,8 +1047,11 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too ###################################################################### def current_notetype_is_image_occlusion(self) -> bool: - return bool(self.note) and ( - self.note.note_type().get("originalStockKind", None) + if not self.note: + return False + + return ( + self.note_type().get("originalStockKind", None) == StockNotetype.OriginalStockKind.ORIGINAL_STOCK_KIND_IMAGE_OCCLUSION ) @@ -1049,6 +1062,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too image_path=image_path, notetype_id=0 ) else: + assert self.note is not None self.setup_mask_editor_for_existing_note( note_id=self.note.id, image_path=image_path ) @@ -1075,8 +1089,10 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too def select_image_from_clipboard_and_occlude(self) -> None: """Set up the mask editor for the image in the clipboard.""" - clipoard = self.mw.app.clipboard() - mime = clipoard.mimeData() + clipboard = self.mw.app.clipboard() + assert clipboard is not None + mime = clipboard.mimeData() + assert mime is not None if not mime.hasImage(): showWarning(tr.editing_no_image_found_on_clipboard()) return @@ -1160,6 +1176,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too @deprecated(info=_js_legacy) def _onHtmlEdit(self, field: int) -> None: + assert self.note is not None d = QDialog(self.widget, Qt.WindowType.Window) form = aqt.forms.edithtml.Ui_Dialog() form.setupUi(d) @@ -1223,7 +1240,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too @deprecated(info=_js_legacy) def _onCloze(self) -> None: # check that the model is set up for cloze deletion - if self.note.note_type()["type"] != MODEL_CLOZE: + if self.note_type()["type"] != MODEL_CLOZE: if self.addMode: tooltip(tr.editing_warning_cloze_deletions_will_not_work()) else: @@ -1231,7 +1248,8 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too return # find the highest existing cloze highest = 0 - for name, val in list(self.note.items()): + assert self.note is not None + for _, val in list(self.note.items()): m = re.findall(r"\{\{c(\d+)::", val) if m: highest = max(highest, sorted(int(x) for x in m)[-1]) @@ -1243,6 +1261,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too self.web.eval("wrap('{{c%d::', '}}');" % highest) def setupForegroundButton(self) -> None: + assert self.mw.pm.profile is not None self.fcolour = self.mw.pm.profile.get("lastColour", "#00f") # use last colour @@ -1276,6 +1295,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too @deprecated(info=_js_legacy) def onColourChanged(self) -> None: self._updateForegroundButton() + assert self.mw.pm.profile is not None self.mw.pm.profile["lastColour"] = self.fcolour @deprecated(info=_js_legacy) @@ -1300,6 +1320,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too (tr.editing_edit_html(), self.onHtmlEdit, "Ctrl+Shift+X"), ): a = m.addAction(text) + assert a is not None qconnect(a.triggered, handler) a.setShortcut(QKeySequence(shortcut)) @@ -1387,6 +1408,12 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too addImageForOcclusionFromClipboard=Editor.select_image_from_clipboard_and_occlude, ) + def note_type(self) -> NotetypeDict: + assert self.note is not None + note_type = self.note.note_type() + assert note_type is not None + return note_type + # Pasting, drag & drop, and keyboard layouts ###################################################################### @@ -1403,6 +1430,7 @@ class EditorWebView(AnkiWebView): self._internal_field_text_for_paste: str | None = None self._last_known_clipboard_mime: QMimeData | None = None clip = self.editor.mw.app.clipboard() + assert clip is not None clip.dataChanged.connect(self._on_clipboard_change) gui_hooks.editor_web_view_did_init(self) @@ -1411,7 +1439,7 @@ class EditorWebView(AnkiWebView): self._internal_field_text_for_paste = None def _on_clipboard_change(self) -> None: - self._last_known_clipboard_mime = self.editor.mw.app.clipboard().mimeData() + self._last_known_clipboard_mime = self._clipboard().mimeData() if self._store_field_content_on_next_clipboard_change: # if the flag was set, save the field data self._internal_field_text_for_paste = self._get_clipboard_html_for_field() @@ -1423,8 +1451,9 @@ class EditorWebView(AnkiWebView): self._internal_field_text_for_paste = None def _get_clipboard_html_for_field(self): - clip = self.editor.mw.app.clipboard() + clip = self._clipboard() mime = clip.mimeData() + assert mime is not None if not mime.hasHtml(): return return mime.html() @@ -1440,6 +1469,7 @@ class EditorWebView(AnkiWebView): def _opened_context_menu_on_image(self) -> bool: context_menu_request = self.lastContextMenuRequest() + assert context_menu_request is not None return ( context_menu_request.mediaType() == context_menu_request.MediaType.MediaTypeImage @@ -1455,7 +1485,8 @@ class EditorWebView(AnkiWebView): def _onPaste(self, mode: QClipboard.Mode) -> None: # Since _on_clipboard_change doesn't always trigger properly on macOS, we do a double check if any changes were made before pasting - if self._last_known_clipboard_mime != self.editor.mw.app.clipboard().mimeData(): + clipboard = self._clipboard() + if self._last_known_clipboard_mime != clipboard.mimeData(): self._on_clipboard_change() extended = self._wantsExtendedPaste() if html := self._internal_field_text_for_paste: @@ -1463,7 +1494,8 @@ class EditorWebView(AnkiWebView): self.editor.doPaste(html, True, extended) else: print("use clipboard") - mime = self.editor.mw.app.clipboard().mimeData(mode=mode) + mime = clipboard.mimeData(mode=mode) + assert mime is not None html, internal = self._processMime(mime, extended) if html: self.editor.doPaste(html, internal, extended) @@ -1474,12 +1506,15 @@ class EditorWebView(AnkiWebView): def onMiddleClickPaste(self) -> None: self._onPaste(QClipboard.Mode.Selection) - def dragEnterEvent(self, evt: QDragEnterEvent) -> None: + def dragEnterEvent(self, evt: QDragEnterEvent | None) -> None: + assert evt is not None evt.accept() - def dropEvent(self, evt: QDropEvent) -> None: + def dropEvent(self, evt: QDropEvent | None) -> None: + assert evt is not None extended = self._wantsExtendedPaste() mime = evt.mimeData() + assert mime is not None cursor_pos = self.mapFromGlobal(QCursor.pos()) if evt.source() and mime.hasHtml(): @@ -1585,12 +1620,13 @@ class EditorWebView(AnkiWebView): return fname - def contextMenuEvent(self, evt: QContextMenuEvent) -> None: + def contextMenuEvent(self, evt: QContextMenuEvent | None) -> None: m = QMenu(self) if self.hasSelection(): self._add_cut_action(m) self._add_copy_action(m) a = m.addAction(tr.editing_paste()) + assert a is not None qconnect(a.triggered, self.onPaste) if self._opened_context_menu_on_image(): self._add_image_menu(m) @@ -1599,26 +1635,38 @@ class EditorWebView(AnkiWebView): def _add_cut_action(self, menu: QMenu) -> None: a = menu.addAction(tr.editing_cut()) + assert a is not None qconnect(a.triggered, self.onCut) def _add_copy_action(self, menu: QMenu) -> None: a = menu.addAction(tr.actions_copy()) + assert a is not None qconnect(a.triggered, self.onCopy) def _add_image_menu(self, menu: QMenu) -> None: a = menu.addAction(tr.editing_copy_image()) + assert a is not None qconnect(a.triggered, self.on_copy_image) - url = self.lastContextMenuRequest().mediaUrl() + context_menu_request = self.lastContextMenuRequest() + assert context_menu_request is not None + url = context_menu_request.mediaUrl() file_name = url.fileName() path = os.path.join(self.editor.mw.col.media.dir(), file_name) a = menu.addAction(tr.editing_open_image()) + assert a is not None qconnect(a.triggered, lambda: openFolder(path)) if is_win or is_mac: a = menu.addAction(tr.editing_show_in_folder()) + assert a is not None qconnect(a.triggered, lambda: show_in_folder(path)) + def _clipboard(self) -> QClipboard: + clipboard = self.editor.mw.app.clipboard() + assert clipboard is not None + return clipboard + # QFont returns "Kozuka Gothic Pro L" but WebEngine expects "Kozuka Gothic Pro Light" # - there may be other cases like a trailing 'Bold' that need fixing, but will @@ -1648,7 +1696,7 @@ gui_hooks.editor_will_munge_html.append(reverse_url_quoting) def set_cloze_button(editor: Editor) -> None: - action = "show" if editor.note.note_type()["type"] == MODEL_CLOZE else "hide" + action = "show" if editor.note_type()["type"] == MODEL_CLOZE else "hide" editor.web.eval( 'require("anki/ui").loaded.then(() =>' f'require("anki/NoteEditor").instances[0].toolbar.toolbar.{action}("cloze")' From f804abf758971d3598a24e382811ccca0a9213b1 Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Tue, 15 Oct 2024 23:16:47 +0800 Subject: [PATCH 010/113] Fix/only let FSRS take over short-term schedule when steps are empty (#3496) --- rslib/src/scheduler/fsrs/retention.rs | 2 +- rslib/src/scheduler/states/learning.rs | 15 ++++++++++++--- rslib/src/scheduler/states/relearning.rs | 18 +++++++++--------- rslib/src/scheduler/states/review.rs | 2 +- rslib/src/scheduler/states/steps.rs | 4 ++++ 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/rslib/src/scheduler/fsrs/retention.rs b/rslib/src/scheduler/fsrs/retention.rs index 60506c233..f9716dde0 100644 --- a/rslib/src/scheduler/fsrs/retention.rs +++ b/rslib/src/scheduler/fsrs/retention.rs @@ -63,7 +63,7 @@ impl Collection { .is_ok() }, )? - .clamp(0.75, 0.95)) + .clamp(0.7, 0.95)) } pub fn get_optimal_retention_parameters( diff --git a/rslib/src/scheduler/states/learning.rs b/rslib/src/scheduler/states/learning.rs index 83a2f7b32..57b610afc 100644 --- a/rslib/src/scheduler/states/learning.rs +++ b/rslib/src/scheduler/states/learning.rs @@ -49,7 +49,10 @@ impl LearnState { } else { let (minimum, maximum) = ctx.min_and_max_review_intervals(1); let (interval, short_term) = if let Some(states) = &ctx.fsrs_next_states { - (states.again.interval, states.again.interval < 0.5) + ( + states.again.interval, + ctx.steps.is_empty() && states.again.interval < 0.5, + ) } else { (ctx.graduating_interval_good as f32, false) }; @@ -91,7 +94,10 @@ impl LearnState { } else { let (minimum, maximum) = ctx.min_and_max_review_intervals(1); let (interval, short_term) = if let Some(states) = &ctx.fsrs_next_states { - (states.hard.interval, states.hard.interval < 0.5) + ( + states.hard.interval, + ctx.steps.is_empty() && states.hard.interval < 0.5, + ) } else { (ctx.graduating_interval_good as f32, false) }; @@ -133,7 +139,10 @@ impl LearnState { } else { let (minimum, maximum) = ctx.min_and_max_review_intervals(1); let (interval, short_term) = if let Some(states) = &ctx.fsrs_next_states { - (states.good.interval, states.good.interval < 0.5) + ( + states.good.interval, + ctx.steps.is_empty() && states.good.interval < 0.5, + ) } else { (ctx.graduating_interval_good as f32, false) }; diff --git a/rslib/src/scheduler/states/relearning.rs b/rslib/src/scheduler/states/relearning.rs index 79c021b10..0659d18e2 100644 --- a/rslib/src/scheduler/states/relearning.rs +++ b/rslib/src/scheduler/states/relearning.rs @@ -68,10 +68,10 @@ impl RelearnState { }, review: again_review, }; - if interval > 0.5 { - again_review.into() - } else { + if ctx.relearn_steps.is_empty() && interval < 0.5 { again_relearn.into() + } else { + again_review.into() } } else { self.review.into() @@ -112,10 +112,10 @@ impl RelearnState { }, review: hard_review, }; - if interval > 0.5 { - hard_review.into() - } else { + if ctx.relearn_steps.is_empty() && interval < 0.5 { hard_relearn.into() + } else { + hard_review.into() } } else { self.review.into() @@ -162,10 +162,10 @@ impl RelearnState { }, review: good_review, }; - if interval > 0.5 { - good_review.into() - } else { + if ctx.relearn_steps.is_empty() && interval < 0.5 { good_relearn.into() + } else { + good_review.into() } } else { self.review.into() diff --git a/rslib/src/scheduler/states/review.rs b/rslib/src/scheduler/states/review.rs index 9382d9264..7f7a215f1 100644 --- a/rslib/src/scheduler/states/review.rs +++ b/rslib/src/scheduler/states/review.rs @@ -124,7 +124,7 @@ impl ReviewState { review: again_review, } .into() - } else if scheduled_days < 0.5 { + } else if ctx.relearn_steps.is_empty() && scheduled_days < 0.5 { again_relearn.into() } else { again_review.into() diff --git a/rslib/src/scheduler/states/steps.rs b/rslib/src/scheduler/states/steps.rs index 1dd70532c..6c62bd0d1 100644 --- a/rslib/src/scheduler/states/steps.rs +++ b/rslib/src/scheduler/states/steps.rs @@ -83,6 +83,10 @@ impl<'a> LearningSteps<'a> { pub(crate) fn remaining_for_failed(self) -> u32 { self.steps.len() as u32 } + + pub(crate) fn is_empty(&self) -> bool { + self.steps.is_empty() + } } /// If the given interval in seconds surpasses 1 day, rounds it to a whole From 569a4705e71173c887d0ac6b13d3614b6189e989 Mon Sep 17 00:00:00 2001 From: Taylor Obyen <162023405+taylorobyen@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:46:55 -0400 Subject: [PATCH 011/113] Fix ease button alignment (#3474) * Fix ease button alignment * Make CSS not 'hacky' --- qt/aqt/data/web/css/reviewer-bottom.scss | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/qt/aqt/data/web/css/reviewer-bottom.scss b/qt/aqt/data/web/css/reviewer-bottom.scss index 59098a5fb..ac07d4d80 100644 --- a/qt/aqt/data/web/css/reviewer-bottom.scss +++ b/qt/aqt/data/web/css/reviewer-bottom.scss @@ -23,6 +23,16 @@ body { position: relative; } +#innertable > tbody > tr { + display: flex; + align-items: stretch; + justify-content: center; +} + +#innertable > tbody > tr > td { + flex: 1; +} + button { min-width: 60px; white-space: nowrap; From 25070c505a5c35c2582ecdd69ead0d1e6b27574b Mon Sep 17 00:00:00 2001 From: Han Yeong-woo Date: Wed, 16 Oct 2024 01:35:37 +0900 Subject: [PATCH 012/113] Fully switch to File::set_times() from utime crate (#3503) * Fully switch to File::set_times() from utime crate * Switch to open_file() Future me will end up wondering why we're explicitly declaring read=true * Fix failing on windows * Minor tidy-up (dae) * Fix comment typo --- Cargo.lock | 11 ---------- Cargo.toml | 1 - cargo/licenses.json | 9 --------- rslib/Cargo.toml | 1 - rslib/io/src/lib.rs | 20 +++++++++++++++++-- .../media/database/client/changetracker.rs | 13 ++++++------ 6 files changed, 24 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea3c70c7a..38bcdd6f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,7 +171,6 @@ dependencies = [ "unic-ucd-category", "unicase", "unicode-normalization", - "utime", "windows 0.56.0", "wiremock", "zip", @@ -6422,16 +6421,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "utime" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91baa0c65eabd12fcbdac8cc35ff16159cab95cae96d0222d6d0271db6193cef" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "uuid" version = "1.10.0" diff --git a/Cargo.toml b/Cargo.toml index 6d86959f0..8d3c0052b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,6 @@ ninja_gen = { "path" = "build/ninja_gen" } # pinned unicase = "=2.6.0" # any changes could invalidate sqlite indexes -utime = "=0.3.1" # marked as deprecated, but no native solution for folder mtimes exists # normal ammonia = "4.0.0" diff --git a/cargo/licenses.json b/cargo/licenses.json index 911b0944c..83bbcf653 100644 --- a/cargo/licenses.json +++ b/cargo/licenses.json @@ -4238,15 +4238,6 @@ "license_file": null, "description": "Incremental, zero-copy UTF-8 decoding with error handling" }, - { - "name": "utime", - "version": "0.3.1", - "authors": "Hyeon Kim ", - "repository": "https://github.com/simnalamburt/utime", - "license": "Apache-2.0 OR MIT", - "license_file": null, - "description": "A missing utime function for Rust." - }, { "name": "uuid", "version": "1.10.0", diff --git a/rslib/Cargo.toml b/rslib/Cargo.toml index fb14826b4..1c4abf46f 100644 --- a/rslib/Cargo.toml +++ b/rslib/Cargo.toml @@ -103,7 +103,6 @@ tracing-subscriber.workspace = true unic-ucd-category.workspace = true unicase.workspace = true unicode-normalization.workspace = true -utime.workspace = true zip.workspace = true zstd.workspace = true diff --git a/rslib/io/src/lib.rs b/rslib/io/src/lib.rs index f9ee9758a..100d397d3 100644 --- a/rslib/io/src/lib.rs +++ b/rslib/io/src/lib.rs @@ -53,9 +53,25 @@ pub fn write_file(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result< op: FileOp::Write, }) } -/// See [File::set_times]. Note that this won't work on folders. + +/// See [File::set_times]. pub fn set_file_times(path: impl AsRef, times: FileTimes) -> Result<()> { - let file = open_file_ext(&path, OpenOptions::new().write(true).to_owned())?; + #[cfg(not(windows))] + let file = open_file(&path)?; + + #[cfg(windows)] + let file = { + use std::os::windows::fs::OpenOptionsExt; + open_file_ext( + &path, + OpenOptions::new() + .write(true) + // It's required to modify the time attributes of a directory in windows system. + .custom_flags(0x02000000) // FILE_FLAG_BACKUP_SEMANTICS + .to_owned(), + )? + }; + file.set_times(times).context(FileIoSnafu { path: path.as_ref(), op: FileOp::SetFileTimes, diff --git a/rslib/src/sync/media/database/client/changetracker.rs b/rslib/src/sync/media/database/client/changetracker.rs index 7f9b3f3cd..2d2220c7c 100644 --- a/rslib/src/sync/media/database/client/changetracker.rs +++ b/rslib/src/sync/media/database/client/changetracker.rs @@ -239,11 +239,13 @@ where #[cfg(test)] mod test { use std::fs; + use std::fs::FileTimes; use std::path::Path; use std::time; use std::time::Duration; use anki_io::create_dir; + use anki_io::set_file_times; use anki_io::write_file; use tempfile::tempdir; @@ -257,13 +259,10 @@ mod test { fn change_mtime(p: &Path) { let mtime = p.metadata().unwrap().modified().unwrap(); let new_mtime = mtime - Duration::from_secs(3); - let secs = new_mtime - .duration_since(time::UNIX_EPOCH) - .unwrap() - .as_secs() as i64; - // we rely on an external crate, as Rust's File::set_times() does not work - // on directories - utime::set_file_times(p, secs, secs).unwrap(); + let times = FileTimes::new() + .set_accessed(new_mtime) + .set_modified(new_mtime); + set_file_times(p, times).unwrap(); } #[test] From c1a2b03871058067cda13681c87b24979f484913 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Wed, 16 Oct 2024 03:02:22 +1000 Subject: [PATCH 013/113] Revert "NF: Improve typing of AnkiWebView action (#3475)" (#3504) This reverts commit 18889239d2e72bc5247d73eb957b964372527c79. --- qt/aqt/webview.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index 55b7f3971..50c4fdfe7 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -8,9 +8,9 @@ import json import os import re import sys -from collections.abc import Callable +from collections.abc import Callable, Sequence from enum import Enum -from typing import TYPE_CHECKING, Any, Optional, cast +from typing import TYPE_CHECKING, Any, cast import anki import anki.lang @@ -285,7 +285,7 @@ class AnkiWebView(QWebEngineView): self.onBridgeCmd: Callable[[str], Any] = self.defaultOnBridgeCmd self._domDone = True - self._pendingActions: list[Callable[[], None]] = [] + self._pendingActions: list[tuple[str, Sequence[Any]]] = [] self.requiresCol = True self.setPage(self._page) self._disable_zoom = False @@ -395,13 +395,14 @@ class AnkiWebView(QWebEngineView): def setHtml( # type: ignore[override] self, html: str, context: PageContext | None = None ) -> None: + from aqt.mediasrv import PageContext # discard any previous pending actions self._pendingActions = [] self._domDone = True if context is None: context = PageContext.UNKNOWN - self._queueAction(lambda: self._setHtml(html, context)) + self._queueAction("setHtml", html, context) self.set_open_links_externally(True) self.allow_drops = False self.show() @@ -630,10 +631,10 @@ html {{ {font} }} def eval(self, js: str) -> None: self.evalWithCallback(js, None) - def evalWithCallback(self, js: str, cb: Optional[Callable]) -> None: - self._queueAction(lambda: self._evalWithCallback(js, cb)) + def evalWithCallback(self, js: str, cb: Callable) -> None: + self._queueAction("eval", js, cb) - def _evalWithCallback(self, js: str, cb: Optional[Callable[[Any], Any]]) -> None: + def _evalWithCallback(self, js: str, cb: Callable[[Any], Any]) -> None: if cb: def handler(val: Any) -> None: @@ -646,16 +647,22 @@ html {{ {font} }} else: self.page().runJavaScript(js) - def _queueAction(self, action: Callable[[], None]) -> None: - self._pendingActions.append(action) + def _queueAction(self, name: str, *args: Any) -> None: + self._pendingActions.append((name, args)) self._maybeRunActions() def _maybeRunActions(self) -> None: if sip.isdeleted(self): return while self._pendingActions and self._domDone: - action = self._pendingActions.pop(0) - action() + name, args = self._pendingActions.pop(0) + + if name == "eval": + self._evalWithCallback(*args) + elif name == "setHtml": + self._setHtml(*args) + else: + raise Exception(f"unknown action: {name}") def _openLinksExternally(self, url: str) -> None: openLink(url) From b09326cddd21938505e0de89928f9326cb41679d Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Fri, 18 Oct 2024 16:57:06 +0800 Subject: [PATCH 014/113] Feat/export dataset for research (#3511) * Feat/export dataset for research * add comment Co-authored-by: Damien Elmes * target_path is required * format * improve efficiency to look up parent_id * move `use` down --- proto/anki/scheduler.proto | 7 +++ proto/anki/stats.proto | 20 ++++++-- pylib/anki/collection.py | 5 ++ rslib/src/scheduler/fsrs/weights.rs | 56 ++++++++++++++++++----- rslib/src/scheduler/service/mod.rs | 9 ++++ rslib/src/storage/card/get_card_entry.sql | 7 +++ rslib/src/storage/card/mod.rs | 16 +++++++ 7 files changed, 105 insertions(+), 15 deletions(-) create mode 100644 rslib/src/storage/card/get_card_entry.sql diff --git a/proto/anki/scheduler.proto b/proto/anki/scheduler.proto index 1bacd0d1f..e0e653082 100644 --- a/proto/anki/scheduler.proto +++ b/proto/anki/scheduler.proto @@ -67,6 +67,8 @@ service BackendSchedulerService { returns (ComputeFsrsWeightsResponse); // Generates parameters used for FSRS's scheduler benchmarks. rpc FsrsBenchmark(FsrsBenchmarkRequest) returns (FsrsBenchmarkResponse); + // Used for exporting revlogs for algorithm research. + rpc ExportDataset(ExportDatasetRequest) returns (generic.Empty); } message SchedulingState { @@ -363,6 +365,11 @@ message FsrsBenchmarkResponse { repeated float weights = 1; } +message ExportDatasetRequest { + uint32 min_entries = 1; + string target_path = 2; +} + message FsrsItem { repeated FsrsReview reviews = 1; } diff --git a/proto/anki/stats.proto b/proto/anki/stats.proto index 4ef811df9..14d0eef6f 100644 --- a/proto/anki/stats.proto +++ b/proto/anki/stats.proto @@ -217,7 +217,21 @@ message RevlogEntry { ReviewKind review_kind = 9; } -message RevlogEntries { - repeated RevlogEntry entries = 1; - int64 next_day_at = 2; +message CardEntry { + int64 id = 1; + int64 note_id = 2; + int64 deck_id = 3; +} + +message DeckEntry { + int64 id = 1; + int64 parent_id = 2; + int64 preset_id = 3; +} + +message Dataset { + repeated RevlogEntry revlogs = 1; + repeated CardEntry cards = 2; + repeated DeckEntry decks = 3; + int64 next_day_at = 4; } diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index 27c01e0e1..559434cda 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -420,6 +420,11 @@ class Collection(DeprecatedNamesMixin): def import_json_string(self, json: str) -> ImportLogWithChanges: return self._backend.import_json_string(json) + def export_dataset_for_research( + self, target_path: str, min_entries: int = 0 + ) -> None: + self._backend.export_dataset(min_entries=min_entries, target_path=target_path) + # Image Occlusion ########################################################################## diff --git a/rslib/src/scheduler/fsrs/weights.rs b/rslib/src/scheduler/fsrs/weights.rs index 51bd7107d..3350487e4 100644 --- a/rslib/src/scheduler/fsrs/weights.rs +++ b/rslib/src/scheduler/fsrs/weights.rs @@ -1,5 +1,6 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +use std::collections::HashMap; use std::iter; use std::path::Path; use std::thread; @@ -8,7 +9,8 @@ use std::time::Duration; use anki_io::write_file; use anki_proto::scheduler::ComputeFsrsWeightsResponse; use anki_proto::stats::revlog_entry; -use anki_proto::stats::RevlogEntries; +use anki_proto::stats::Dataset; +use anki_proto::stats::DeckEntry; use chrono::NaiveDate; use chrono::NaiveTime; use fsrs::CombinedProgressState; @@ -19,6 +21,7 @@ use fsrs::FSRS; use itertools::Itertools; use prost::Message; +use crate::decks::immediate_parent_name; use crate::prelude::*; use crate::revlog::RevlogEntry; use crate::revlog::RevlogReviewKind; @@ -127,22 +130,51 @@ impl Collection { } /// Used for exporting revlogs for algorithm research. - pub fn export_revlog_entries_to_protobuf( - &mut self, - min_entries: usize, - target_path: &Path, - ) -> Result<()> { - let entries = self.storage.get_all_revlog_entries_in_card_order()?; - if entries.len() < min_entries { + pub fn export_dataset(&mut self, min_entries: usize, target_path: &Path) -> Result<()> { + let revlog_entries = self.storage.get_all_revlog_entries_in_card_order()?; + if revlog_entries.len() < min_entries { return Err(AnkiError::FsrsInsufficientData); } - let entries = entries.into_iter().map(revlog_entry_to_proto).collect_vec(); + let revlogs = revlog_entries + .into_iter() + .map(revlog_entry_to_proto) + .collect_vec(); + let cards = self.storage.get_all_card_entries()?; + + let decks_map = self.storage.get_decks_map()?; + let deck_name_to_id: HashMap = decks_map + .into_iter() + .map(|(id, deck)| (deck.name.to_string(), id)) + .collect(); + + let decks = self + .storage + .get_all_decks()? + .into_iter() + .filter_map(|deck| { + if let Some(preset_id) = deck.config_id().map(|id| id.0) { + let parent_id = immediate_parent_name(&deck.name.to_string()) + .and_then(|parent_name| deck_name_to_id.get(parent_name)) + .map(|id| id.0) + .unwrap_or(0); + Some(DeckEntry { + id: deck.id.0, + parent_id, + preset_id, + }) + } else { + None + } + }) + .collect_vec(); let next_day_at = self.timing_today()?.next_day_at.0; - let entries = RevlogEntries { - entries, + let dataset = Dataset { + revlogs, + cards, + decks, next_day_at, }; - let data = entries.encode_to_vec(); + let data = dataset.encode_to_vec(); write_file(target_path, data)?; Ok(()) } diff --git a/rslib/src/scheduler/service/mod.rs b/rslib/src/scheduler/service/mod.rs index 9cce0c44e..aa71d4829 100644 --- a/rslib/src/scheduler/service/mod.rs +++ b/rslib/src/scheduler/service/mod.rs @@ -368,6 +368,15 @@ impl crate::services::BackendSchedulerService for Backend { let weights = fsrs.benchmark(train_set); Ok(FsrsBenchmarkResponse { weights }) } + + fn export_dataset(&self, req: scheduler::ExportDatasetRequest) -> Result<()> { + self.with_col(|col| { + col.export_dataset( + req.min_entries.try_into().unwrap(), + req.target_path.as_ref(), + ) + }) + } } fn fsrs_item_proto_to_fsrs(item: anki_proto::scheduler::FsrsItem) -> FSRSItem { diff --git a/rslib/src/storage/card/get_card_entry.sql b/rslib/src/storage/card/get_card_entry.sql new file mode 100644 index 000000000..d7d76ab87 --- /dev/null +++ b/rslib/src/storage/card/get_card_entry.sql @@ -0,0 +1,7 @@ +SELECT id, + nid, + CASE + WHEN odid = 0 THEN did + ELSE odid + END AS did +FROM cards; \ No newline at end of file diff --git a/rslib/src/storage/card/mod.rs b/rslib/src/storage/card/mod.rs index f290a7f71..51263a8b1 100644 --- a/rslib/src/storage/card/mod.rs +++ b/rslib/src/storage/card/mod.rs @@ -9,6 +9,7 @@ use std::convert::TryFrom; use std::fmt; use std::result; +use anki_proto::stats::CardEntry; use rusqlite::named_params; use rusqlite::params; use rusqlite::types::FromSql; @@ -87,6 +88,14 @@ fn row_to_card(row: &Row) -> result::Result { }) } +fn row_to_card_entry(row: &Row) -> Result { + Ok(CardEntry { + id: row.get(0)?, + note_id: row.get(1)?, + deck_id: row.get(2)?, + }) +} + fn row_to_new_card(row: &Row) -> result::Result { Ok(NewCard { id: row.get(0)?, @@ -108,6 +117,13 @@ impl super::SqliteStorage { .map_err(Into::into) } + pub(crate) fn get_all_card_entries(&self) -> Result> { + self.db + .prepare_cached(include_str!("get_card_entry.sql"))? + .query_and_then([], row_to_card_entry)? + .collect() + } + pub(crate) fn update_card(&self, card: &Card) -> Result<()> { let mut stmt = self.db.prepare_cached(include_str!("update_card.sql"))?; stmt.execute(params![ From 6ff309e08f027e91fb3f065679ac3ef02057ba34 Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Mon, 21 Oct 2024 13:09:07 +0800 Subject: [PATCH 015/113] Feat/option to enable FSRS short-term scheduler when (re)learning steps run out && speed up features based on simulation (#3505) * Update to FSRS-rs v1.3.2 * add fsrs_short_term_with_steps_enabled to config * ./ninja fix:minilints * fix defaults_for_testing * if current parameters are invalid, skip comparison fix #3498 * fix redundant_field_names * cargo clippy --fix * Update to FSRS-rs v1.3.3 * Update to FSRS-rs v1.3.4 * Avoid an extra config lookup on each card answer (dae) --- Cargo.lock | 16 ++++++++++++++-- Cargo.toml | 2 +- cargo/licenses.json | 11 ++++++++++- proto/anki/config.proto | 2 ++ pylib/anki/collection.py | 10 ++++++++++ rslib/src/backend/config.rs | 1 + rslib/src/config/bool.rs | 1 + rslib/src/preferences.rs | 7 ++++++- rslib/src/scheduler/answering/mod.rs | 5 +++++ rslib/src/scheduler/fsrs/weights.rs | 15 ++++++++------- rslib/src/scheduler/states/learning.rs | 9 ++++++--- rslib/src/scheduler/states/mod.rs | 2 ++ rslib/src/scheduler/states/relearning.rs | 12 +++++++++--- rslib/src/scheduler/states/review.rs | 4 +++- 14 files changed, 78 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38bcdd6f6..83ce00bfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1860,15 +1860,16 @@ dependencies = [ [[package]] name = "fsrs" -version = "1.3.1" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2434366942bf285f3c0691e68d731e56f4e1fc1d8ec7b6a0e9411e94eda6ffbd" +checksum = "a05b1fdbaa34f9bcd605ad50477eea51b27b3f60f973021bd9ee1b5943169150" dependencies = [ "burn", "itertools 0.12.1", "log", "ndarray", "ndarray-rand", + "priority-queue", "rand", "rayon", "serde", @@ -4276,6 +4277,17 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "priority-queue" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714c75db297bc88a63783ffc6ab9f830698a6705aa0201416931759ef4c8183d" +dependencies = [ + "autocfg", + "equivalent", + "indexmap", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" diff --git a/Cargo.toml b/Cargo.toml index 8d3c0052b..dc1d3a5f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ git = "https://github.com/ankitects/linkcheck.git" rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca" [workspace.dependencies.fsrs] -version = "=1.3.1" +version = "=1.3.4" # git = "https://github.com/open-spaced-repetition/fsrs-rs.git" # rev = "58ca25ed2bc4bb1dc376208bbcaed7f5a501b941" # path = "../open-spaced-repetition/fsrs-rs" diff --git a/cargo/licenses.json b/cargo/licenses.json index 83bbcf653..9054526ad 100644 --- a/cargo/licenses.json +++ b/cargo/licenses.json @@ -1225,7 +1225,7 @@ }, { "name": "fsrs", - "version": "1.3.1", + "version": "1.3.4", "authors": "Open Spaced Repetition", "repository": "https://github.com/open-spaced-repetition/fsrs-rs", "license": "BSD-3-Clause", @@ -2753,6 +2753,15 @@ "license_file": null, "description": "A minimal `syn` syntax tree pretty-printer" }, + { + "name": "priority-queue", + "version": "2.1.1", + "authors": "Gianmarco Garrisi ", + "repository": "https://github.com/garro95/priority-queue", + "license": "LGPL-3.0-or-later OR MPL-2.0", + "license_file": null, + "description": "A Priority Queue implemented as a heap with a function to efficiently change the priority of an item." + }, { "name": "proc-macro-crate", "version": "3.2.0", diff --git a/proto/anki/config.proto b/proto/anki/config.proto index 9924ab90f..d61f139d6 100644 --- a/proto/anki/config.proto +++ b/proto/anki/config.proto @@ -55,6 +55,7 @@ message ConfigKey { SHIFT_POSITION_OF_EXISTING_CARDS = 24; RENDER_LATEX = 25; LOAD_BALANCER_ENABLED = 26; + FSRS_SHORT_TERM_WITH_STEPS_ENABLED = 27; } enum String { SET_DUE_BROWSER = 0; @@ -117,6 +118,7 @@ message Preferences { bool show_intervals_on_buttons = 4; uint32 time_limit_secs = 5; bool load_balancer_enabled = 6; + bool fsrs_short_term_with_steps_enabled = 7; } message Editing { bool adding_defaults_to_current_deck = 1; diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index 559434cda..208ed6448 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -992,6 +992,16 @@ class Collection(DeprecatedNamesMixin): fget=_get_enable_load_balancer, fset=_set_enable_load_balancer ) + def _get_enable_fsrs_short_term_with_steps(self) -> bool: + return self.get_config_bool(Config.Bool.FSRS_SHORT_TERM_WITH_STEPS_ENABLED) + + def _set_enable_fsrs_short_term_with_steps(self, value: bool) -> None: + self.set_config_bool(Config.Bool.FSRS_SHORT_TERM_WITH_STEPS_ENABLED, value) + + fsrs_short_term_with_steps_enabled = property( + fget=_get_enable_fsrs_short_term_with_steps, + fset=_set_enable_fsrs_short_term_with_steps, + ) # Stats ########################################################################## diff --git a/rslib/src/backend/config.rs b/rslib/src/backend/config.rs index 137124b45..6e0bed153 100644 --- a/rslib/src/backend/config.rs +++ b/rslib/src/backend/config.rs @@ -38,6 +38,7 @@ impl From for BoolKey { BoolKeyProto::ShiftPositionOfExistingCards => BoolKey::ShiftPositionOfExistingCards, BoolKeyProto::RenderLatex => BoolKey::RenderLatex, BoolKeyProto::LoadBalancerEnabled => BoolKey::LoadBalancerEnabled, + BoolKeyProto::FsrsShortTermWithStepsEnabled => BoolKey::FsrsShortTermWithStepsEnabled, } } } diff --git a/rslib/src/config/bool.rs b/rslib/src/config/bool.rs index c946f7c34..b430babe4 100644 --- a/rslib/src/config/bool.rs +++ b/rslib/src/config/bool.rs @@ -41,6 +41,7 @@ pub enum BoolKey { WithDeckConfigs, Fsrs, LoadBalancerEnabled, + FsrsShortTermWithStepsEnabled, #[strum(to_string = "normalize_note_text")] NormalizeNoteText, #[strum(to_string = "dayLearnFirst")] diff --git a/rslib/src/preferences.rs b/rslib/src/preferences.rs index e3b7e6f3c..96be8e461 100644 --- a/rslib/src/preferences.rs +++ b/rslib/src/preferences.rs @@ -99,6 +99,8 @@ impl Collection { .get_config_bool(BoolKey::ShowIntervalsAboveAnswerButtons), time_limit_secs: self.get_answer_time_limit_secs(), load_balancer_enabled: self.get_config_bool(BoolKey::LoadBalancerEnabled), + fsrs_short_term_with_steps_enabled: self + .get_config_bool(BoolKey::FsrsShortTermWithStepsEnabled), }) } @@ -119,7 +121,10 @@ impl Collection { )?; self.set_answer_time_limit_secs(s.time_limit_secs)?; self.set_config_bool_inner(BoolKey::LoadBalancerEnabled, s.load_balancer_enabled)?; - + self.set_config_bool_inner( + BoolKey::FsrsShortTermWithStepsEnabled, + s.fsrs_short_term_with_steps_enabled, + )?; Ok(()) } diff --git a/rslib/src/scheduler/answering/mod.rs b/rslib/src/scheduler/answering/mod.rs index 5e85dce1f..169205b31 100644 --- a/rslib/src/scheduler/answering/mod.rs +++ b/rslib/src/scheduler/answering/mod.rs @@ -73,6 +73,7 @@ struct CardStateUpdater { fsrs_next_states: Option, /// Set if FSRS is enabled. desired_retention: Option, + fsrs_short_term_with_steps: bool, } impl CardStateUpdater { @@ -110,6 +111,7 @@ impl CardStateUpdater { Default::default() }, fsrs_next_states: self.fsrs_next_states.clone(), + fsrs_short_term_with_steps_enabled: self.fsrs_short_term_with_steps, } } @@ -458,6 +460,8 @@ impl Collection { None }; let desired_retention = fsrs_enabled.then_some(config.inner.desired_retention); + let fsrs_short_term_with_steps = + self.get_config_bool(BoolKey::FsrsShortTermWithStepsEnabled); Ok(CardStateUpdater { fuzz_seed: get_fuzz_seed(&card, false), card, @@ -467,6 +471,7 @@ impl Collection { now: TimestampSecs::now(), fsrs_next_states, desired_retention, + fsrs_short_term_with_steps, }) } diff --git a/rslib/src/scheduler/fsrs/weights.rs b/rslib/src/scheduler/fsrs/weights.rs index 3350487e4..5fbe59172 100644 --- a/rslib/src/scheduler/fsrs/weights.rs +++ b/rslib/src/scheduler/fsrs/weights.rs @@ -97,13 +97,14 @@ impl Collection { } } }); - let fsrs = FSRS::new(Some(current_weights))?; - let current_rmse = fsrs.evaluate(items.clone(), |_| true)?.rmse_bins; - let mut weights = fsrs.compute_parameters(items.clone(), Some(progress2))?; - let optimized_fsrs = FSRS::new(Some(&weights))?; - let optimized_rmse = optimized_fsrs.evaluate(items.clone(), |_| true)?.rmse_bins; - if current_rmse <= optimized_rmse { - weights = current_weights.to_vec(); + let mut weights = FSRS::new(None)?.compute_parameters(items.clone(), Some(progress2))?; + if let Ok(fsrs) = FSRS::new(Some(current_weights)) { + let current_rmse = fsrs.evaluate(items.clone(), |_| true)?.rmse_bins; + let optimized_fsrs = FSRS::new(Some(&weights))?; + let optimized_rmse = optimized_fsrs.evaluate(items.clone(), |_| true)?.rmse_bins; + if current_rmse <= optimized_rmse { + weights = current_weights.to_vec(); + } } Ok(ComputeFsrsWeightsResponse { diff --git a/rslib/src/scheduler/states/learning.rs b/rslib/src/scheduler/states/learning.rs index 57b610afc..0dc5782be 100644 --- a/rslib/src/scheduler/states/learning.rs +++ b/rslib/src/scheduler/states/learning.rs @@ -51,7 +51,8 @@ impl LearnState { let (interval, short_term) = if let Some(states) = &ctx.fsrs_next_states { ( states.again.interval, - ctx.steps.is_empty() && states.again.interval < 0.5, + (ctx.fsrs_short_term_with_steps_enabled || ctx.steps.is_empty()) + && states.again.interval < 0.5, ) } else { (ctx.graduating_interval_good as f32, false) @@ -96,7 +97,8 @@ impl LearnState { let (interval, short_term) = if let Some(states) = &ctx.fsrs_next_states { ( states.hard.interval, - ctx.steps.is_empty() && states.hard.interval < 0.5, + (ctx.fsrs_short_term_with_steps_enabled || ctx.steps.is_empty()) + && states.hard.interval < 0.5, ) } else { (ctx.graduating_interval_good as f32, false) @@ -141,7 +143,8 @@ impl LearnState { let (interval, short_term) = if let Some(states) = &ctx.fsrs_next_states { ( states.good.interval, - ctx.steps.is_empty() && states.good.interval < 0.5, + (ctx.fsrs_short_term_with_steps_enabled || ctx.steps.is_empty()) + && states.good.interval < 0.5, ) } else { (ctx.graduating_interval_good as f32, false) diff --git a/rslib/src/scheduler/states/mod.rs b/rslib/src/scheduler/states/mod.rs index b721e1da2..527298a87 100644 --- a/rslib/src/scheduler/states/mod.rs +++ b/rslib/src/scheduler/states/mod.rs @@ -88,6 +88,7 @@ pub(crate) struct StateContext<'a> { /// range. pub fuzz_factor: Option, pub fsrs_next_states: Option, + pub fsrs_short_term_with_steps_enabled: bool, // learning pub steps: LearningSteps<'a>, @@ -147,6 +148,7 @@ impl<'a> StateContext<'a> { good: 0, }, fsrs_next_states: None, + fsrs_short_term_with_steps_enabled: false, } } } diff --git a/rslib/src/scheduler/states/relearning.rs b/rslib/src/scheduler/states/relearning.rs index 0659d18e2..31ffe5710 100644 --- a/rslib/src/scheduler/states/relearning.rs +++ b/rslib/src/scheduler/states/relearning.rs @@ -68,7 +68,9 @@ impl RelearnState { }, review: again_review, }; - if ctx.relearn_steps.is_empty() && interval < 0.5 { + if (ctx.fsrs_short_term_with_steps_enabled || ctx.relearn_steps.is_empty()) + && interval < 0.5 + { again_relearn.into() } else { again_review.into() @@ -112,7 +114,9 @@ impl RelearnState { }, review: hard_review, }; - if ctx.relearn_steps.is_empty() && interval < 0.5 { + if (ctx.fsrs_short_term_with_steps_enabled || ctx.relearn_steps.is_empty()) + && interval < 0.5 + { hard_relearn.into() } else { hard_review.into() @@ -162,7 +166,9 @@ impl RelearnState { }, review: good_review, }; - if ctx.relearn_steps.is_empty() && interval < 0.5 { + if (ctx.fsrs_short_term_with_steps_enabled || ctx.relearn_steps.is_empty()) + && interval < 0.5 + { good_relearn.into() } else { good_review.into() diff --git a/rslib/src/scheduler/states/review.rs b/rslib/src/scheduler/states/review.rs index 7f7a215f1..f173c2310 100644 --- a/rslib/src/scheduler/states/review.rs +++ b/rslib/src/scheduler/states/review.rs @@ -124,7 +124,9 @@ impl ReviewState { review: again_review, } .into() - } else if ctx.relearn_steps.is_empty() && scheduled_days < 0.5 { + } else if (ctx.fsrs_short_term_with_steps_enabled || ctx.relearn_steps.is_empty()) + && scheduled_days < 0.5 + { again_relearn.into() } else { again_review.into() From b0eb2a2b9759e7fbbe91ad7a84ec3665b4304412 Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Mon, 21 Oct 2024 13:19:42 +0800 Subject: [PATCH 016/113] Feat/Estimated Total Knowledge By Note & Daily Load (#3507) * Feat/Estimated Total Knowledge By Note & Daily Load * Update rslib/src/stats/graphs/retrievability.rs * Update rslib/src/stats/graphs/future_due.rs --- ftl/core/statistics.ftl | 6 ++++++ proto/anki/stats.proto | 4 +++- rslib/src/stats/graphs/future_due.rs | 7 +++++++ rslib/src/stats/graphs/retrievability.rs | 26 +++++++++++++++++------- ts/routes/graphs/future-due.ts | 13 +++++++++++- ts/routes/graphs/retrievability.ts | 10 ++++++--- 6 files changed, 54 insertions(+), 12 deletions(-) diff --git a/ftl/core/statistics.ftl b/ftl/core/statistics.ftl index f84e5a13f..006db0cf5 100644 --- a/ftl/core/statistics.ftl +++ b/ftl/core/statistics.ftl @@ -48,6 +48,11 @@ statistics-cards = [one] { $cards } card *[other] { $cards } cards } +statistics-notes = + { $notes -> + [one] { $notes } note + *[other] { $notes } notes + } # a count of how many cards have been answered, eg "Total: 34 reviews" statistics-reviews = { $reviews -> @@ -220,6 +225,7 @@ statistics-average-answer-time-label = Average answer time statistics-average = Average statistics-average-interval = Average interval statistics-due-tomorrow = Due tomorrow +statistics-daily-load = Daily load # eg 5 of 15 (33.3%) statistics-amount-of-total-with-percentage = { $amount } of { $total } ({ $percent }%) statistics-average-over-period = Average over period diff --git a/proto/anki/stats.proto b/proto/anki/stats.proto index 14d0eef6f..63799b071 100644 --- a/proto/anki/stats.proto +++ b/proto/anki/stats.proto @@ -85,11 +85,13 @@ message GraphsResponse { message Retrievability { map retrievability = 1; float average = 2; - float sum = 3; + float sum_by_card = 3; + float sum_by_note = 4; } message FutureDue { map future_due = 1; bool have_backlog = 2; + uint32 daily_load = 3; } message Today { uint32 answer_count = 1; diff --git a/rslib/src/stats/graphs/future_due.rs b/rslib/src/stats/graphs/future_due.rs index 4671766e5..2b7caec5e 100644 --- a/rslib/src/stats/graphs/future_due.rs +++ b/rslib/src/stats/graphs/future_due.rs @@ -13,6 +13,7 @@ impl GraphsContext { pub(super) fn future_due(&self) -> FutureDue { let mut have_backlog = false; let mut due_by_day: HashMap = Default::default(); + let mut daily_load = 0.0; for c in &self.cards { if matches!(c.queue, CardQueue::New | CardQueue::Suspended) { continue; @@ -31,10 +32,16 @@ impl GraphsContext { } have_backlog |= due_day < 0; *due_by_day.entry(due_day).or_default() += 1; + if matches!(c.queue, CardQueue::Review | CardQueue::DayLearn) { + daily_load += 1.0 / c.interval.max(1) as f32; + } else { + daily_load += 1.0; + } } FutureDue { future_due: due_by_day, have_backlog, + daily_load: daily_load as u32, } } } diff --git a/rslib/src/stats/graphs/retrievability.rs b/rslib/src/stats/graphs/retrievability.rs index da2830e8f..930a21c5b 100644 --- a/rslib/src/stats/graphs/retrievability.rs +++ b/rslib/src/stats/graphs/retrievability.rs @@ -19,25 +19,37 @@ impl GraphsContext { next_day_at: Default::default(), }; let fsrs = FSRS::new(None).unwrap(); + // note id -> (sum, count) + let mut note_retrievability: std::collections::HashMap = + std::collections::HashMap::new(); for card in &self.cards { + let entry = note_retrievability + .entry(card.note_id.0) + .or_insert((0.0, 0)); + entry.1 += 1; if let Some(state) = card.memory_state { - let r = fsrs.current_retrievability( - state.into(), - card.days_since_last_review(&timing).unwrap_or_default(), - ); + let elapsed_days = card.days_since_last_review(&timing).unwrap_or_default(); + let r = fsrs.current_retrievability(state.into(), elapsed_days); + *retrievability .retrievability .entry(percent_to_bin(r * 100.0)) .or_insert_with(Default::default) += 1; - retrievability.sum += r; + retrievability.sum_by_card += r; card_with_retrievability_count += 1; + entry.0 += r; + } else { + entry.0 += 0.0; } } if card_with_retrievability_count != 0 { retrievability.average = - retrievability.sum * 100.0 / card_with_retrievability_count as f32; + retrievability.sum_by_card * 100.0 / card_with_retrievability_count as f32; } - + retrievability.sum_by_note = note_retrievability + .values() + .map(|(sum, count)| sum / *count as f32) + .sum(); retrievability } } diff --git a/ts/routes/graphs/future-due.ts b/ts/routes/graphs/future-due.ts index 1acd221f5..b965874c5 100644 --- a/ts/routes/graphs/future-due.ts +++ b/ts/routes/graphs/future-due.ts @@ -19,11 +19,16 @@ import type { HistogramData } from "./histogram-graph"; export interface GraphData { dueCounts: Map; haveBacklog: boolean; + dailyLoad: number; } export function gatherData(data: GraphsResponse): GraphData { const msg = data.futureDue!; - return { dueCounts: numericMap(msg.futureDue), haveBacklog: msg.haveBacklog }; + return { + dueCounts: numericMap(msg.futureDue), + haveBacklog: msg.haveBacklog, + dailyLoad: msg.dailyLoad, + }; } export interface FutureDueResponse { @@ -138,6 +143,12 @@ export function buildHistogram( reviews: sourceData.dueCounts.get(1) ?? 0, }), }, + { + label: tr.statisticsDailyLoad(), + value: tr.statisticsReviews({ + reviews: sourceData.dailyLoad, + }), + }, ]; return { diff --git a/ts/routes/graphs/retrievability.ts b/ts/routes/graphs/retrievability.ts index 072e6ab73..dd54c2b8d 100644 --- a/ts/routes/graphs/retrievability.ts +++ b/ts/routes/graphs/retrievability.ts @@ -18,14 +18,16 @@ import type { HistogramData } from "./histogram-graph"; export interface GraphData { retrievability: Map; average: number; - sum: number; + sumByCard: number; + sumByNote: number; } export function gatherData(data: GraphsResponse): GraphData { return { retrievability: numericMap(data.retrievability!.retrievability), average: data.retrievability!.average, - sum: data.retrievability!.sum, + sumByCard: data.retrievability!.sumByCard, + sumByNote: data.retrievability!.sumByNote, }; } @@ -111,7 +113,9 @@ export function prepareData( }, { label: tr.statisticsEstimatedTotalKnowledge(), - value: tr.statisticsCards({ cards: +data.sum.toFixed(0) }), + value: `${tr.statisticsCards({ cards: +data.sumByCard.toFixed(0) })} / ${ + tr.statisticsNotes({ notes: +data.sumByNote.toFixed(0) }) + }`, }, ]; From 84b6d20e1d84958e08226dc990aa1d8ad87a6d07 Mon Sep 17 00:00:00 2001 From: sorata <136738526+brishtibheja@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:50:45 +0530 Subject: [PATCH 017/113] change sort order name (#3510) --- ftl/core/deck-config.ftl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ftl/core/deck-config.ftl b/ftl/core/deck-config.ftl index 1d202cb82..4a90216f4 100644 --- a/ftl/core/deck-config.ftl +++ b/ftl/core/deck-config.ftl @@ -152,7 +152,7 @@ deck-config-new-gather-priority-tooltip-2 = `Random cards`: Gathers cards in a random order. deck-config-new-gather-priority-deck = Deck -deck-config-new-gather-priority-deck-then-random-notes = Deck then random notes +deck-config-new-gather-priority-deck-then-random-notes = Deck, then random notes deck-config-new-gather-priority-position-lowest-first = Ascending position deck-config-new-gather-priority-position-highest-first = Descending position deck-config-new-gather-priority-random-notes = Random notes @@ -207,8 +207,8 @@ deck-config-sort-order-ascending-intervals = Ascending intervals deck-config-sort-order-descending-intervals = Descending intervals deck-config-sort-order-ascending-ease = Ascending ease deck-config-sort-order-descending-ease = Descending ease -deck-config-sort-order-ascending-difficulty = Ascending difficulty -deck-config-sort-order-descending-difficulty = Descending difficulty +deck-config-sort-order-ascending-difficulty = Easy cards first +deck-config-sort-order-descending-difficulty = Difficult cards first deck-config-sort-order-relative-overdueness = Relative overdueness deck-config-display-order-will-use-current-deck = Anki will use the display order from the deck you From 30e734b9253a1a1e073be9cf65ca082f35bbf181 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 21 Oct 2024 13:38:29 +1000 Subject: [PATCH 018/113] Bump Rust deps Primarily for prost, which had incompatible changes --- Cargo.lock | 218 ++++++++++++++-------------- Cargo.toml | 68 ++++----- cargo/licenses.json | 38 ++--- rslib/proto/rust.rs | 4 +- rslib/src/stats/graphs/retention.rs | 12 +- 5 files changed, 170 insertions(+), 170 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83ce00bfe..1385d889c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -130,7 +130,7 @@ dependencies = [ "futures", "hex", "htmlescape", - "hyper 1.4.1", + "hyper 1.5.0", "id_tree", "inflections", "itertools 0.13.0", @@ -160,7 +160,7 @@ dependencies = [ "sha1", "snafu", "strum 0.26.3", - "syn 2.0.79", + "syn 2.0.82", "tempfile", "tokio", "tokio-util", @@ -304,9 +304,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95" [[package]] name = "apple-bundles" @@ -353,9 +353,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.15" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e26a9844c659a2a293d239c7910b752f8487fe122c6c8bd1659bf85a6507c302" +checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" dependencies = [ "futures-core", "memchr", @@ -384,7 +384,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -395,7 +395,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -424,7 +424,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "itoa", "matchit", @@ -509,7 +509,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -780,7 +780,7 @@ dependencies = [ "derive-new", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -919,7 +919,7 @@ checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -999,9 +999,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.30" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "jobserver", "libc", @@ -1110,7 +1110,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1452,7 +1452,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1510,7 +1510,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1577,7 +1577,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1765,9 +1765,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "spin 0.9.8", ] @@ -1805,7 +1805,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1971,7 +1971,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2569,7 +2569,7 @@ dependencies = [ "markup5ever 0.12.1", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2654,9 +2654,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -2678,9 +2678,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -2705,7 +2705,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", @@ -2719,9 +2719,9 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", - "rustls 0.23.14", + "rustls 0.23.15", "rustls-native-certs", "rustls-pki-types", "tokio", @@ -2737,7 +2737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.30", + "hyper 0.14.31", "native-tls", "tokio", "tokio-native-tls", @@ -2751,7 +2751,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "native-tls", "tokio", @@ -2770,7 +2770,7 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "pin-project-lite", "socket2", "tokio", @@ -3075,9 +3075,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libdbus-sys" @@ -3752,7 +3752,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -3809,9 +3809,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -3830,7 +3830,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -3841,9 +3841,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -4022,7 +4022,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -4115,7 +4115,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -4153,7 +4153,7 @@ checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -4269,12 +4269,12 @@ checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "910d41a655dac3b764f1ade94821093d3610248694320cd072303a8eedcf221d" dependencies = [ "proc-macro2", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -4305,9 +4305,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -4320,9 +4320,9 @@ checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" [[package]] name = "prost" -version = "0.12.6" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", "prost-derive", @@ -4330,13 +4330,13 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.12.6" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.12.1", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -4345,28 +4345,28 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.79", + "syn 2.0.82", "tempfile", ] [[package]] name = "prost-derive" -version = "0.12.6" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] name = "prost-reflect" -version = "0.12.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057237efdb71cf4b3f9396302a3d6599a92fa94063ba537b66130980ea9909f3" +checksum = "4b7535b02f0e5efe3e1dbfcb428be152226ed0c66cad9541f2274c8ba8d4cd40" dependencies = [ "once_cell", "prost", @@ -4375,9 +4375,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.12.6" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" dependencies = [ "prost", ] @@ -4438,9 +4438,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.22.4" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e89ce2565d6044ca31a3eb79a334c3a79a841120a98f64eea9f579564cb691" +checksum = "3d922163ba1f79c04bc49073ba7b32fd5a8d3b76a87c955921234b8e77333c51" dependencies = [ "cfg-if", "indoc", @@ -4456,9 +4456,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.22.4" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8afbaf3abd7325e08f35ffb8deb5892046fcb2608b703db6a583a5ba4cea01e" +checksum = "bc38c5feeb496c8321091edf3d63e9a6829eab4b863b4a6a65f26f3e9cc6b179" dependencies = [ "once_cell", "target-lexicon", @@ -4466,9 +4466,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.22.4" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec15a5ba277339d04763f4c23d85987a5b08cbb494860be141e6a10a8eb88022" +checksum = "94845622d88ae274d2729fcefc850e63d7a3ddff5e3ce11bd88486db9f1d357d" dependencies = [ "libc", "pyo3-build-config", @@ -4476,27 +4476,27 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.22.4" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e0f01b5364bcfbb686a52fc4181d412b708a68ed20c330db9fc8d2c2bf5a43" +checksum = "e655aad15e09b94ffdb3ce3d217acf652e26bbc37697ef012f5e5e348c716e5e" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] name = "pyo3-macros-backend" -version = "0.22.4" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a09b550200e1e5ed9176976d0060cbc2ea82dc8515da07885e7b8153a85caacb" +checksum = "ae1e3f09eecd94618f60a455a23def79f79eba4dc561a97324bf9ac8c6df30ce" dependencies = [ "heck 0.5.0", "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -4528,7 +4528,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.14", + "rustls 0.23.15", "socket2", "thiserror", "tokio", @@ -4545,7 +4545,7 @@ dependencies = [ "rand", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.14", + "rustls 0.23.15", "slab", "thiserror", "tinyvec", @@ -4794,7 +4794,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", @@ -4837,7 +4837,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-rustls 0.27.3", "hyper-tls 0.6.0", "hyper-util", @@ -4851,7 +4851,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.14", + "rustls 0.23.15", "rustls-native-certs", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -5015,9 +5015,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.14" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "log", "once_cell", @@ -5255,14 +5255,14 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -5288,7 +5288,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5460,7 +5460,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5572,7 +5572,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5585,7 +5585,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5607,9 +5607,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -5639,7 +5639,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5782,7 +5782,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5905,7 +5905,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5934,7 +5934,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.14", + "rustls 0.23.15", "rustls-pki-types", "tokio", ] @@ -6100,7 +6100,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6300,7 +6300,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.79", + "syn 2.0.82", "unic-langid-impl", ] @@ -6401,7 +6401,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.23.14", + "rustls 0.23.15", "rustls-pki-types", "serde", "serde_json", @@ -6435,9 +6435,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", "rand", @@ -6491,7 +6491,7 @@ dependencies = [ "futures-util", "headers 0.3.9", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "log", "mime", "mime_guess", @@ -6545,7 +6545,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-shared", ] @@ -6579,7 +6579,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6850,7 +6850,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6861,7 +6861,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -7093,7 +7093,7 @@ dependencies = [ "futures", "http 1.1.0", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "log", "once_cell", @@ -7170,7 +7170,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "synstructure", ] @@ -7192,7 +7192,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -7212,7 +7212,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index dc1d3a5f3..4af2c46d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,19 +55,19 @@ unicase = "=2.6.0" # any changes could invalidate sqlite indexes # normal ammonia = "4.0.0" -anyhow = "1.0.86" +anyhow = "1.0.90" apple-bundles = "0.17.0" -async-compression = { version = "0.4.12", features = ["zstd", "tokio"] } -async-stream = "0.3.5" -async-trait = "0.1.82" +async-compression = { version = "0.4.17", features = ["zstd", "tokio"] } +async-stream = "0.3.6" +async-trait = "0.1.83" axum = { version = "0.7", features = ["multipart", "macros"] } axum-client-ip = "0.6" -axum-extra = { version = "0.9.3", features = ["typed-header"] } +axum-extra = { version = "0.9.4", features = ["typed-header"] } blake3 = "1.5.4" -bytes = "1.7.1" +bytes = "1.7.2" camino = "1.1.9" chrono = { version = "0.4.38", default-features = false, features = ["std", "clock"] } -clap = { version = "4.3.24", features = ["derive"] } +clap = { version = "4.5.20", features = ["derive"] } coarsetime = "0.1.34" convert_case = "0.6.0" criterion = { version = "0.5.1" } @@ -77,14 +77,14 @@ difflib = "0.4.0" dirs = "5.0.1" dunce = "1.0.5" envy = "0.4.2" -flate2 = "1.0.33" +flate2 = "1.0.34" fluent = "0.16.1" fluent-bundle = "0.15.3" fluent-syntax = "0.11.1" fnv = "1.0.7" -futures = "0.3.30" +futures = "0.3.31" glob = "0.3.1" -globset = "0.4.14" +globset = "0.4.15" hex = "0.4.3" htmlescape = "0.3.1" hyper = "1" @@ -92,47 +92,47 @@ id_tree = "1.8.0" inflections = "1.1.1" intl-memoizer = "0.5.2" itertools = "0.13.0" -junction = "1.1.0" +junction = "1.2.0" lazy_static = "1.5.0" maplit = "1.0.2" nom = "7.1.3" num-format = "0.4.4" num_cpus = "1.16.0" -num_enum = "0.7.2" -once_cell = "1.19.0" +num_enum = "0.7.3" +once_cell = "1.20.2" pbkdf2 = { version = "0.12", features = ["simple"] } phf = { version = "0.11.2", features = ["macros"] } -pin-project = "1.1.5" -plist = "1.5.1" -prettyplease = "0.2.22" -prost = "0.12.3" -prost-build = "0.12.3" -prost-reflect = "0.12.0" -prost-types = "0.12.3" +pin-project = "1.1.6" +plist = "1.7.0" +prettyplease = "0.2.24" +prost = "0.13" +prost-build = "0.13" +prost-reflect = "0.14" +prost-types = "0.13" pulldown-cmark = "0.9.6" -pyo3 = { version = "0.22.2", features = ["extension-module", "abi3", "abi3-py39"] } +pyo3 = { version = "0.22.5", features = ["extension-module", "abi3", "abi3-py39"] } rand = "0.8.5" -regex = "1.10.6" -reqwest = { version = "0.12.7", default-features = false, features = ["json", "socks", "stream", "multipart"] } +regex = "1.11.0" +reqwest = { version = "0.12.8", default-features = false, features = ["json", "socks", "stream", "multipart"] } rusqlite = { version = "0.30.0", features = ["trace", "functions", "collation", "bundled"] } -rustls-pemfile = "2.1.3" +rustls-pemfile = "2.2.0" scopeguard = "1.2.0" -serde = { version = "1.0.209", features = ["derive"] } +serde = { version = "1.0.210", features = ["derive"] } serde-aux = "4.5.0" -serde_json = "1.0.127" +serde_json = "1.0.132" serde_repr = "0.1.19" serde_tuple = "0.5.0" sha1 = "0.10.6" sha2 = { version = "0.10.8" } simple-file-manifest = "0.11.0" -snafu = { version = "0.8.4", features = ["rust_1_61"] } +snafu = { version = "0.8.5", features = ["rust_1_61"] } strum = { version = "0.26.3", features = ["derive"] } -syn = { version = "2.0.77", features = ["parsing", "printing"] } -tar = "0.4.41" -tempfile = "3.12.0" +syn = { version = "2.0.82", features = ["parsing", "printing"] } +tar = "0.4.42" +tempfile = "3.13.0" termcolor = "1.4.1" -tokio = { version = "1.38", features = ["fs", "rt-multi-thread", "macros", "signal"] } -tokio-util = { version = "0.7.11", features = ["io"] } +tokio = { version = "1.40", features = ["fs", "rt-multi-thread", "macros", "signal"] } +tokio-util = { version = "0.7.12", features = ["io"] } tower-http = { version = "0.5", features = ["trace"] } tracing = { version = "0.1.40", features = ["max_level_trace", "release_max_level_debug"] } tracing-appender = "0.2.3" @@ -140,10 +140,10 @@ tracing-subscriber = { version = "0.3.18", features = ["fmt", "env-filter"] } tugger-windows-codesign = "0.10.0" unic-langid = { version = "0.9.5", features = ["macros"] } unic-ucd-category = "0.9.0" -unicode-normalization = "0.1.23" +unicode-normalization = "0.1.24" walkdir = "2.5.0" which = "5.0.0" -wiremock = "0.6.1" +wiremock = "0.6.2" xz2 = "0.1.7" zip = { version = "0.6.6", default-features = false, features = ["deflate", "time"] } zstd = { version = "0.13.2", features = ["zstdmt"] } diff --git a/cargo/licenses.json b/cargo/licenses.json index 9054526ad..de342bec6 100644 --- a/cargo/licenses.json +++ b/cargo/licenses.json @@ -136,7 +136,7 @@ }, { "name": "anyhow", - "version": "1.0.89", + "version": "1.0.90", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/anyhow", "license": "Apache-2.0 OR MIT", @@ -181,7 +181,7 @@ }, { "name": "async-compression", - "version": "0.4.15", + "version": "0.4.17", "authors": "Wim Looman |Allen Bui ", "repository": "https://github.com/Nullus157/async-compression", "license": "Apache-2.0 OR MIT", @@ -622,7 +622,7 @@ }, { "name": "cc", - "version": "1.1.30", + "version": "1.1.31", "authors": "Alex Crichton ", "repository": "https://github.com/rust-lang/cc-rs", "license": "Apache-2.0 OR MIT", @@ -1144,7 +1144,7 @@ }, { "name": "flume", - "version": "0.11.0", + "version": "0.11.1", "authors": "Joshua Barretto ", "repository": "https://github.com/zesterer/flume", "license": "Apache-2.0 OR MIT", @@ -1756,7 +1756,7 @@ }, { "name": "hyper", - "version": "1.4.1", + "version": "1.5.0", "authors": "Sean McArthur ", "repository": "https://github.com/hyperium/hyper", "license": "MIT", @@ -1990,7 +1990,7 @@ }, { "name": "libc", - "version": "0.2.159", + "version": "0.2.161", "authors": "The Rust Project Developers", "repository": "https://github.com/rust-lang/libc", "license": "Apache-2.0 OR MIT", @@ -2440,7 +2440,7 @@ }, { "name": "openssl", - "version": "0.10.66", + "version": "0.10.68", "authors": "Steven Fackler ", "repository": "https://github.com/sfackler/rust-openssl", "license": "Apache-2.0", @@ -2467,7 +2467,7 @@ }, { "name": "openssl-sys", - "version": "0.9.103", + "version": "0.9.104", "authors": "Alex Crichton |Steven Fackler ", "repository": "https://github.com/sfackler/rust-openssl", "license": "MIT", @@ -2746,7 +2746,7 @@ }, { "name": "prettyplease", - "version": "0.2.22", + "version": "0.2.24", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/prettyplease", "license": "Apache-2.0 OR MIT", @@ -2782,7 +2782,7 @@ }, { "name": "proc-macro2", - "version": "1.0.87", + "version": "1.0.88", "authors": "David Tolnay |Alex Crichton ", "repository": "https://github.com/dtolnay/proc-macro2", "license": "Apache-2.0 OR MIT", @@ -2800,7 +2800,7 @@ }, { "name": "prost", - "version": "0.12.6", + "version": "0.13.3", "authors": "Dan Burkert |Lucio Franco |Casper Meijn |Tokio Contributors ", "repository": "https://github.com/tokio-rs/prost", "license": "Apache-2.0", @@ -2809,7 +2809,7 @@ }, { "name": "prost-build", - "version": "0.12.6", + "version": "0.13.3", "authors": "Dan Burkert |Lucio Franco |Casper Meijn |Tokio Contributors ", "repository": "https://github.com/tokio-rs/prost", "license": "Apache-2.0", @@ -2818,7 +2818,7 @@ }, { "name": "prost-derive", - "version": "0.12.6", + "version": "0.13.3", "authors": "Dan Burkert |Lucio Franco |Casper Meijn |Tokio Contributors ", "repository": "https://github.com/tokio-rs/prost", "license": "Apache-2.0", @@ -2827,7 +2827,7 @@ }, { "name": "prost-reflect", - "version": "0.12.0", + "version": "0.14.2", "authors": "Andrew Hickman ", "repository": "https://github.com/andrewhickman/prost-reflect", "license": "Apache-2.0 OR MIT", @@ -2836,7 +2836,7 @@ }, { "name": "prost-types", - "version": "0.12.6", + "version": "0.13.3", "authors": "Dan Burkert |Lucio Franco |Casper Meijn |Tokio Contributors ", "repository": "https://github.com/tokio-rs/prost", "license": "Apache-2.0", @@ -3178,7 +3178,7 @@ }, { "name": "rustls", - "version": "0.23.14", + "version": "0.23.15", "authors": null, "repository": "https://github.com/rustls/rustls", "license": "Apache-2.0 OR ISC OR MIT", @@ -3376,7 +3376,7 @@ }, { "name": "serde_json", - "version": "1.0.128", + "version": "1.0.132", "authors": "Erick Tryzelaar |David Tolnay ", "repository": "https://github.com/serde-rs/json", "license": "Apache-2.0 OR MIT", @@ -3682,7 +3682,7 @@ }, { "name": "syn", - "version": "2.0.79", + "version": "2.0.82", "authors": "David Tolnay ", "repository": "https://github.com/dtolnay/syn", "license": "Apache-2.0 OR MIT", @@ -4249,7 +4249,7 @@ }, { "name": "uuid", - "version": "1.10.0", + "version": "1.11.0", "authors": "Ashley Mannix|Dylan DPC|Hunar Roop Kahlon", "repository": "https://github.com/uuid-rs/uuid", "license": "Apache-2.0 OR MIT", diff --git a/rslib/proto/rust.rs b/rslib/proto/rust.rs index 93012874a..85834f19f 100644 --- a/rslib/proto/rust.rs +++ b/rslib/proto/rust.rs @@ -29,13 +29,13 @@ pub fn write_rust_protos(descriptors_path: PathBuf) -> Result { ) .type_attribute( "Deck.Normal.DayLimit", - "#[derive(Copy, Eq, serde::Deserialize, serde::Serialize)]", + "#[derive(Eq, serde::Deserialize, serde::Serialize)]", ) .type_attribute("HelpPageLinkRequest.HelpPage", "#[derive(strum::EnumIter)]") .type_attribute("CsvMetadata.Delimiter", "#[derive(strum::EnumIter)]") .type_attribute( "Preferences.BackupLimits", - "#[derive(Copy, serde::Deserialize, serde::Serialize)]", + "#[derive(serde::Deserialize, serde::Serialize)]", ) .type_attribute( "CsvMetadata.DupeResolution", diff --git a/rslib/src/stats/graphs/retention.rs b/rslib/src/stats/graphs/retention.rs index 886e42ae5..d1ddbc2d1 100644 --- a/rslib/src/stats/graphs/retention.rs +++ b/rslib/src/stats/graphs/retention.rs @@ -77,12 +77,12 @@ impl GraphsContext { } }); - stats.today = Some(period_stats["today"].clone()); - stats.yesterday = Some(period_stats["yesterday"].clone()); - stats.week = Some(period_stats["week"].clone()); - stats.month = Some(period_stats["month"].clone()); - stats.year = Some(period_stats["year"].clone()); - stats.all_time = Some(period_stats["all_time"].clone()); + stats.today = Some(period_stats["today"]); + stats.yesterday = Some(period_stats["yesterday"]); + stats.week = Some(period_stats["week"]); + stats.month = Some(period_stats["month"]); + stats.year = Some(period_stats["year"]); + stats.all_time = Some(period_stats["all_time"]); stats } From 26ae51fafdab7e062d040f669a09c6e1016ddbeb Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Mon, 21 Oct 2024 14:47:01 +0800 Subject: [PATCH 019/113] Create a new kind of revlog entry for reschedule cards on change (#3508) * create a new kind of revlog entry for Reschedule cards on change * add comments * exclude the rescheduled case in reviews graph --- ftl/core/card-stats.ftl | 1 + proto/anki/stats.proto | 1 + rslib/src/revlog/mod.rs | 24 +++++++++++++++++++++- rslib/src/scheduler/fsrs/memory_state.rs | 17 +++++++-------- rslib/src/scheduler/fsrs/retention.rs | 3 ++- rslib/src/scheduler/fsrs/weights.rs | 8 +++++++- rslib/src/stats/graphs/buttons.rs | 2 +- rslib/src/stats/graphs/hours.rs | 4 +++- rslib/src/stats/graphs/retention.rs | 2 +- rslib/src/stats/graphs/reviews.rs | 6 ++++-- rslib/src/stats/graphs/today.rs | 6 ++++-- rslib/src/stats/service.rs | 3 +++ rslib/src/storage/revlog/mod.rs | 19 +++++++++++------ rslib/src/storage/revlog/studied_today.sql | 1 + ts/routes/card-info/Revlog.svelte | 2 ++ ts/routes/card-info/forgetting-curve.ts | 1 + 16 files changed, 76 insertions(+), 24 deletions(-) diff --git a/ftl/core/card-stats.ftl b/ftl/core/card-stats.ftl index ece08b20a..bd5b52a87 100644 --- a/ftl/core/card-stats.ftl +++ b/ftl/core/card-stats.ftl @@ -23,6 +23,7 @@ card-stats-review-log-type-review = Review card-stats-review-log-type-relearn = Relearn card-stats-review-log-type-filtered = Filtered card-stats-review-log-type-manual = Manual +card-stats-review-log-type-rescheduled = Rescheduled card-stats-review-log-elapsed-time = Elapsed Time card-stats-no-card = (No card to display.) card-stats-custom-data = Custom Data diff --git a/proto/anki/stats.proto b/proto/anki/stats.proto index 63799b071..a5e3401cc 100644 --- a/proto/anki/stats.proto +++ b/proto/anki/stats.proto @@ -207,6 +207,7 @@ message RevlogEntry { RELEARNING = 2; FILTERED = 3; MANUAL = 4; + RESCHEDULED = 5; } int64 id = 1; int64 cid = 2; diff --git a/rslib/src/revlog/mod.rs b/rslib/src/revlog/mod.rs index 128beab64..ad7f30261 100644 --- a/rslib/src/revlog/mod.rs +++ b/rslib/src/revlog/mod.rs @@ -72,6 +72,7 @@ pub enum RevlogReviewKind { /// disabled. Filtered = 3, Manual = 4, + Rescheduled = 5, } impl RevlogEntry { @@ -86,11 +87,32 @@ impl RevlogEntry { } impl Collection { + // set due date or reset pub(crate) fn log_manually_scheduled_review( &mut self, card: &Card, original_interval: u32, usn: Usn, + ) -> Result<()> { + self.log_scheduled_review(card, original_interval, usn, RevlogReviewKind::Manual) + } + + // reschedule cards on change + pub(crate) fn log_rescheduled_review( + &mut self, + card: &Card, + original_interval: u32, + usn: Usn, + ) -> Result<()> { + self.log_scheduled_review(card, original_interval, usn, RevlogReviewKind::Rescheduled) + } + + fn log_scheduled_review( + &mut self, + card: &Card, + original_interval: u32, + usn: Usn, + review_kind: RevlogReviewKind, ) -> Result<()> { let ease_factor = u32::from( card.memory_state @@ -106,7 +128,7 @@ impl Collection { last_interval: i32::try_from(original_interval).unwrap_or(i32::MAX), ease_factor, taken_millis: 0, - review_kind: RevlogReviewKind::Manual, + review_kind, }; self.add_revlog_entry_undoable(entry)?; Ok(()) diff --git a/rslib/src/scheduler/fsrs/memory_state.rs b/rslib/src/scheduler/fsrs/memory_state.rs index 977368379..8dec27ba8 100644 --- a/rslib/src/scheduler/fsrs/memory_state.rs +++ b/rslib/src/scheduler/fsrs/memory_state.rs @@ -119,9 +119,10 @@ impl Collection { }; *due = (timing.days_elapsed as i32) - days_elapsed + card.interval as i32; - // Add a manual revlog entry if the last entry wasn't manual - if !last_info.last_revlog_is_manual { - self.log_manually_scheduled_review( + // Add a rescheduled revlog entry if the last entry wasn't + // rescheduled + if !last_info.last_revlog_is_rescheduled { + self.log_rescheduled_review( &card, original_interval, usn, @@ -237,7 +238,7 @@ struct LastRevlogInfo { last_reviewed_at: Option, /// If true, the last action on this card was a reschedule, so we /// can avoid writing an extra revlog entry on another reschedule. - last_revlog_is_manual: bool, + last_revlog_is_rescheduled: bool, } /// Return a map of cards to info about last review/reschedule. @@ -249,18 +250,18 @@ fn get_last_revlog_info(revlogs: &[RevlogEntry]) -> HashMap= 1 { last_reviewed_at = Some(e.id.as_secs()); } - last_revlog_is_manual = e.review_kind == RevlogReviewKind::Manual; + last_revlog_is_rescheduled = e.review_kind == RevlogReviewKind::Rescheduled; } out.insert( card_id, LastRevlogInfo { last_reviewed_at, - last_revlog_is_manual, + last_revlog_is_rescheduled, }, ); }); @@ -321,7 +322,7 @@ pub(crate) fn single_card_revlog_to_item( })) } } else { - // only manual rescheduling; treat like empty + // only manual and rescheduled revlogs; treat like empty Ok(None) } } else { diff --git a/rslib/src/scheduler/fsrs/retention.rs b/rslib/src/scheduler/fsrs/retention.rs index f9716dde0..f2951f2dc 100644 --- a/rslib/src/scheduler/fsrs/retention.rs +++ b/rslib/src/scheduler/fsrs/retention.rs @@ -84,7 +84,8 @@ impl From for fsrs::RevlogReviewKind { crate::revlog::RevlogReviewKind::Review => fsrs::RevlogReviewKind::Review, crate::revlog::RevlogReviewKind::Relearning => fsrs::RevlogReviewKind::Relearning, crate::revlog::RevlogReviewKind::Filtered => fsrs::RevlogReviewKind::Filtered, - crate::revlog::RevlogReviewKind::Manual => fsrs::RevlogReviewKind::Manual, + crate::revlog::RevlogReviewKind::Manual + | crate::revlog::RevlogReviewKind::Rescheduled => fsrs::RevlogReviewKind::Manual, } } } diff --git a/rslib/src/scheduler/fsrs/weights.rs b/rslib/src/scheduler/fsrs/weights.rs index 5fbe59172..0c370fbe0 100644 --- a/rslib/src/scheduler/fsrs/weights.rs +++ b/rslib/src/scheduler/fsrs/weights.rs @@ -294,6 +294,9 @@ pub(crate) fn single_card_revlog_to_items( Some(RevlogEntry { review_kind: RevlogReviewKind::Manual, .. + }) | Some(RevlogEntry { + review_kind: RevlogReviewKind::Rescheduled, + .. }) ); } @@ -343,10 +346,12 @@ pub(crate) fn single_card_revlog_to_items( // Filter out unwanted entries entries.retain(|entry| { !( - // manually rescheduled + // set due date or reset (entry.review_kind == RevlogReviewKind::Manual || entry.button_chosen == 0) || // cram (entry.review_kind == RevlogReviewKind::Filtered && entry.ease_factor == 0) + || // rescheduled + (entry.review_kind == RevlogReviewKind::Rescheduled) ) }); @@ -407,6 +412,7 @@ fn revlog_entry_to_proto(e: RevlogEntry) -> anki_proto::stats::RevlogEntry { RevlogReviewKind::Relearning => revlog_entry::ReviewKind::Relearning, RevlogReviewKind::Filtered => revlog_entry::ReviewKind::Filtered, RevlogReviewKind::Manual => revlog_entry::ReviewKind::Manual, + RevlogReviewKind::Rescheduled => revlog_entry::ReviewKind::Rescheduled, } as i32, } } diff --git a/rslib/src/stats/graphs/buttons.rs b/rslib/src/stats/graphs/buttons.rs index 1fa3de759..7c6fd03c8 100644 --- a/rslib/src/stats/graphs/buttons.rs +++ b/rslib/src/stats/graphs/buttons.rs @@ -79,7 +79,7 @@ fn interval_bucket(review: &RevlogEntry) -> Option { } else { IntervalBucket::Mature }), - RevlogReviewKind::Manual => None, + RevlogReviewKind::Manual | RevlogReviewKind::Rescheduled => None, } } diff --git a/rslib/src/stats/graphs/hours.rs b/rslib/src/stats/graphs/hours.rs index b24e5082d..5fcd2ea2d 100644 --- a/rslib/src/stats/graphs/hours.rs +++ b/rslib/src/stats/graphs/hours.rs @@ -32,7 +32,9 @@ impl GraphsContext { 'outer: for review in &self.revlog { if matches!( review.review_kind, - RevlogReviewKind::Filtered | RevlogReviewKind::Manual + RevlogReviewKind::Filtered + | RevlogReviewKind::Manual + | RevlogReviewKind::Rescheduled ) { continue; } diff --git a/rslib/src/stats/graphs/retention.rs b/rslib/src/stats/graphs/retention.rs index d1ddbc2d1..c21f43301 100644 --- a/rslib/src/stats/graphs/retention.rs +++ b/rslib/src/stats/graphs/retention.rs @@ -53,7 +53,7 @@ impl GraphsContext { self.revlog .iter() .filter(|review| { - // not manually rescheduled + // not rescheduled/set due date/reset review.button_chosen > 0 // not cramming && (review.review_kind != RevlogReviewKind::Filtered || review.ease_factor != 0) diff --git a/rslib/src/stats/graphs/reviews.rs b/rslib/src/stats/graphs/reviews.rs index 9db4b9e5d..7c78dabae 100644 --- a/rslib/src/stats/graphs/reviews.rs +++ b/rslib/src/stats/graphs/reviews.rs @@ -10,7 +10,9 @@ impl GraphsContext { pub(super) fn review_counts_and_times(&self) -> ReviewCountsAndTimes { let mut data = ReviewCountsAndTimes::default(); for review in &self.revlog { - if review.review_kind == RevlogReviewKind::Manual { + if review.review_kind == RevlogReviewKind::Manual + || review.review_kind == RevlogReviewKind::Rescheduled + { continue; } let day = (review.id.as_secs().elapsed_secs_since(self.next_day_start) / 86_400) as i32; @@ -38,7 +40,7 @@ impl GraphsContext { count.filtered += 1; time.filtered += review.taken_millis; } - RevlogReviewKind::Manual => unreachable!(), + RevlogReviewKind::Manual | RevlogReviewKind::Rescheduled => unreachable!(), } } data diff --git a/rslib/src/stats/graphs/today.rs b/rslib/src/stats/graphs/today.rs index e2544509a..5ae4d2937 100644 --- a/rslib/src/stats/graphs/today.rs +++ b/rslib/src/stats/graphs/today.rs @@ -14,7 +14,9 @@ impl GraphsContext { if review.id.0 < start_of_today_ms { continue; } - if review.review_kind == RevlogReviewKind::Manual { + if review.review_kind == RevlogReviewKind::Manual + || review.review_kind == RevlogReviewKind::Rescheduled + { continue; } // total @@ -37,7 +39,7 @@ impl GraphsContext { RevlogReviewKind::Review => today.review_count += 1, RevlogReviewKind::Relearning => today.relearn_count += 1, RevlogReviewKind::Filtered => today.early_review_count += 1, - RevlogReviewKind::Manual => unreachable!(), + RevlogReviewKind::Manual | RevlogReviewKind::Rescheduled => unreachable!(), } } today diff --git a/rslib/src/stats/service.rs b/rslib/src/stats/service.rs index 2611ae0bf..077fd38fa 100644 --- a/rslib/src/stats/service.rs +++ b/rslib/src/stats/service.rs @@ -46,6 +46,9 @@ impl From for i32 { RevlogReviewKind::Relearning => anki_proto::stats::revlog_entry::ReviewKind::Relearning, RevlogReviewKind::Filtered => anki_proto::stats::revlog_entry::ReviewKind::Filtered, RevlogReviewKind::Manual => anki_proto::stats::revlog_entry::ReviewKind::Manual, + RevlogReviewKind::Rescheduled => { + anki_proto::stats::revlog_entry::ReviewKind::Rescheduled + } }) as i32 } } diff --git a/rslib/src/storage/revlog/mod.rs b/rslib/src/storage/revlog/mod.rs index 03b72b8b1..84332b0d0 100644 --- a/rslib/src/storage/revlog/mod.rs +++ b/rslib/src/storage/revlog/mod.rs @@ -172,12 +172,19 @@ impl SqliteStorage { let start = day_cutoff.adding_secs(-86_400).as_millis(); self.db .prepare_cached(include_str!("studied_today.sql"))? - .query_map([start.0, RevlogReviewKind::Manual as i64], |row| { - Ok(StudiedToday { - cards: row.get(0)?, - seconds: row.get(1)?, - }) - })? + .query_map( + [ + start.0, + RevlogReviewKind::Manual as i64, + RevlogReviewKind::Rescheduled as i64, + ], + |row| { + Ok(StudiedToday { + cards: row.get(0)?, + seconds: row.get(1)?, + }) + }, + )? .next() .unwrap() .map_err(Into::into) diff --git a/rslib/src/storage/revlog/studied_today.sql b/rslib/src/storage/revlog/studied_today.sql index 2a341f632..7772992d8 100644 --- a/rslib/src/storage/revlog/studied_today.sql +++ b/rslib/src/storage/revlog/studied_today.sql @@ -2,4 +2,5 @@ SELECT COUNT(), coalesce(sum(time) / 1000.0, 0.0) FROM revlog WHERE id > ? + AND type != ? AND type != ? \ No newline at end of file diff --git a/ts/routes/card-info/Revlog.svelte b/ts/routes/card-info/Revlog.svelte index 61f4a5978..dc410b4ab 100644 --- a/ts/routes/card-info/Revlog.svelte +++ b/ts/routes/card-info/Revlog.svelte @@ -36,6 +36,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html return tr2.cardStatsReviewLogTypeFiltered(); case ReviewKind.MANUAL: return tr2.cardStatsReviewLogTypeManual(); + case ReviewKind.RESCHEDULED: + return tr2.cardStatsReviewLogTypeRescheduled(); } } diff --git a/ts/routes/card-info/forgetting-curve.ts b/ts/routes/card-info/forgetting-curve.ts index 7331f7dc5..66d4ebb4f 100644 --- a/ts/routes/card-info/forgetting-curve.ts +++ b/ts/routes/card-info/forgetting-curve.ts @@ -48,6 +48,7 @@ function filterDataByTimeRange(data: DataPoint[], maxDays: number): DataPoint[] export function filterRevlogEntryByReviewKind(entry: RevlogEntry): boolean { return ( entry.reviewKind !== RevlogEntry_ReviewKind.MANUAL + && entry.reviewKind !== RevlogEntry_ReviewKind.RESCHEDULED && (entry.reviewKind !== RevlogEntry_ReviewKind.FILTERED || entry.ease !== 0) ); } From c45fa518d2c0f1d07aff47eadc559c72be7b43c8 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 21 Oct 2024 17:45:45 +1000 Subject: [PATCH 020/113] Use separate field to store FSRS params Will allow the user to keep using old params with older clients --- proto/anki/deck_config.proto | 6 ++++-- rslib/src/deckconfig/mod.rs | 12 ++++++++++- rslib/src/deckconfig/schema11.rs | 14 ++++++++---- rslib/src/deckconfig/update.rs | 26 +++++++++++++++++------ rslib/src/scheduler/answering/mod.rs | 2 +- rslib/src/scheduler/fsrs/memory_state.rs | 2 +- rslib/src/stats/card.rs | 2 +- ts/routes/deck-options/FsrsOptions.svelte | 24 +++++++++++---------- ts/routes/deck-options/lib.ts | 8 +++++++ 9 files changed, 68 insertions(+), 28 deletions(-) diff --git a/proto/anki/deck_config.proto b/proto/anki/deck_config.proto index 179e98b3e..1ac48c969 100644 --- a/proto/anki/deck_config.proto +++ b/proto/anki/deck_config.proto @@ -107,9 +107,11 @@ message DeckConfig { repeated float learn_steps = 1; repeated float relearn_steps = 2; - repeated float fsrs_weights = 3; + repeated float fsrs_params_4 = 3; + repeated float fsrs_params_5 = 5; - reserved 5 to 8; + // consider saving remaining ones for fsrs param changes + reserved 6 to 8; uint32 new_per_day = 9; uint32 reviews_per_day = 10; diff --git a/rslib/src/deckconfig/mod.rs b/rslib/src/deckconfig/mod.rs index 489537d42..ea299da7b 100644 --- a/rslib/src/deckconfig/mod.rs +++ b/rslib/src/deckconfig/mod.rs @@ -74,7 +74,8 @@ const DEFAULT_DECK_CONFIG_INNER: DeckConfigInner = DeckConfigInner { bury_new: false, bury_reviews: false, bury_interday_learning: false, - fsrs_weights: vec![], + fsrs_params_4: vec![], + fsrs_params_5: vec![], desired_retention: 0.9, other: Vec::new(), historical_retention: 0.9, @@ -105,6 +106,15 @@ impl DeckConfig { self.mtime_secs = TimestampSecs::now(); self.usn = usn; } + + /// Retrieve the FSRS 5.0 params, falling back on 4.x ones. + pub fn fsrs_params(&self) -> &Vec { + if self.inner.fsrs_params_5.len() == 19 { + &self.inner.fsrs_params_5 + } else { + &self.inner.fsrs_params_4 + } + } } impl Collection { diff --git a/rslib/src/deckconfig/schema11.rs b/rslib/src/deckconfig/schema11.rs index c03c62d14..bde3f2234 100644 --- a/rslib/src/deckconfig/schema11.rs +++ b/rslib/src/deckconfig/schema11.rs @@ -69,8 +69,10 @@ pub struct DeckConfSchema11 { #[serde(default)] bury_interday_learning: bool, + #[serde(default, rename = "fsrsWeights")] + fsrs_params_4: Vec, #[serde(default)] - fsrs_weights: Vec, + fsrs_params_5: Vec, #[serde(default)] desired_retention: f32, #[serde(default)] @@ -306,7 +308,8 @@ impl Default for DeckConfSchema11 { new_sort_order: 0, new_gather_priority: 0, bury_interday_learning: false, - fsrs_weights: vec![], + fsrs_params_4: vec![], + fsrs_params_5: vec![], desired_retention: 0.9, sm2_retention: 0.9, weight_search: "".to_string(), @@ -386,7 +389,8 @@ impl From for DeckConfig { bury_new: c.new.bury, bury_reviews: c.rev.bury, bury_interday_learning: c.bury_interday_learning, - fsrs_weights: c.fsrs_weights, + fsrs_params_4: c.fsrs_params_4, + fsrs_params_5: c.fsrs_params_5, ignore_revlogs_before_date: c.ignore_revlogs_before_date, easy_days_percentages: c.easy_days_percentages, desired_retention: c.desired_retention, @@ -498,7 +502,8 @@ impl From for DeckConfSchema11 { new_sort_order: i.new_card_sort_order, new_gather_priority: i.new_card_gather_priority, bury_interday_learning: i.bury_interday_learning, - fsrs_weights: i.fsrs_weights, + fsrs_params_4: i.fsrs_params_4, + fsrs_params_5: i.fsrs_params_5, desired_retention: i.desired_retention, sm2_retention: i.historical_retention, weight_search: i.weight_search, @@ -526,6 +531,7 @@ static RESERVED_DECKCONF_KEYS: Set<&'static str> = phf_set! { "interdayLearningMix", "newGatherPriority", "fsrsWeights", + "fsrsParams5", "desiredRetention", "stopTimerOnAnswer", "secondsToShowQuestion", diff --git a/rslib/src/deckconfig/update.rs b/rslib/src/deckconfig/update.rs index dc68b8a39..e931dad4a 100644 --- a/rslib/src/deckconfig/update.rs +++ b/rslib/src/deckconfig/update.rs @@ -50,7 +50,7 @@ impl Collection { deck: DeckId, ) -> Result { let mut defaults = DeckConfig::default(); - defaults.inner.fsrs_weights = DEFAULT_PARAMETERS.into(); + defaults.inner.fsrs_params_5 = DEFAULT_PARAMETERS.into(); let last_optimize = self.get_config_i32(I32ConfigKey::LastFsrsOptimize) as u32; let days_since_last_fsrs_optimize = if last_optimize > 0 { self.timing_today()? @@ -88,6 +88,12 @@ impl Collection { // grab the config and sort it let mut config = self.storage.all_deck_config()?; config.sort_unstable_by(|a, b| a.name.cmp(&b.name)); + // pre-fill empty fsrs 5 params with 4 params + config.iter_mut().for_each(|c| { + if c.inner.fsrs_params_5.is_empty() { + c.inner.fsrs_params_5 = c.inner.fsrs_params_4.clone(); + } + }); // combine with use counts let counts = self.get_deck_config_use_counts()?; @@ -159,8 +165,14 @@ impl Collection { // add/update provided configs for conf in &mut req.configs { + // If the user has provided empty FSRS5 params, zero out any + // old params as well, so we don't fall back on them, which would + // be surprising as they're not shown in the GUI. + if conf.inner.fsrs_params_5.is_empty() { + conf.inner.fsrs_params_4.clear(); + } // check the provided parameters are valid before we save them - FSRS::new(Some(&conf.inner.fsrs_weights))?; + FSRS::new(Some(conf.fsrs_params()))?; self.add_or_update_deck_config(conf)?; configs_after_update.insert(conf.id, conf.clone()); } @@ -201,7 +213,7 @@ impl Collection { let previous_order = previous_config .map(|c| c.inner.new_card_insert_order()) .unwrap_or_default(); - let previous_weights = previous_config.map(|c| &c.inner.fsrs_weights); + let previous_weights = previous_config.map(|c| c.fsrs_params()); let previous_retention = previous_config.map(|c| c.inner.desired_retention); // if a selected (sub)deck, or its old config was removed, update deck to point @@ -228,7 +240,7 @@ impl Collection { } // if weights differ, memory state needs to be recomputed - let current_weights = current_config.map(|c| &c.inner.fsrs_weights); + let current_weights = current_config.map(|c| c.fsrs_params()); let current_retention = current_config.map(|c| c.inner.desired_retention); if fsrs_toggled || previous_weights != current_weights @@ -252,7 +264,7 @@ impl Collection { let weights = config.and_then(|c| { if req.fsrs { Some(UpdateMemoryStateRequest { - weights: c.inner.fsrs_weights.clone(), + weights: c.fsrs_params().clone(), desired_retention: c.inner.desired_retention, max_interval: c.inner.maximum_review_interval, reschedule: req.fsrs_reschedule, @@ -349,11 +361,11 @@ impl Collection { ignore_revlogs_before_ms, idx as u32 + 1, config_len, - &config.inner.fsrs_weights, + config.fsrs_params(), ) { Ok(weights) => { println!("{}: {:?}", config.name, weights.weights); - config.inner.fsrs_weights = weights.weights; + config.inner.fsrs_params_5 = weights.weights; } Err(AnkiError::Interrupted) => return Err(AnkiError::Interrupted), Err(err) => { diff --git a/rslib/src/scheduler/answering/mod.rs b/rslib/src/scheduler/answering/mod.rs index 169205b31..9458e7559 100644 --- a/rslib/src/scheduler/answering/mod.rs +++ b/rslib/src/scheduler/answering/mod.rs @@ -431,7 +431,7 @@ impl Collection { let config = self.home_deck_config(deck.config_id(), card.original_deck_id)?; let fsrs_enabled = self.get_config_bool(BoolKey::Fsrs); let fsrs_next_states = if fsrs_enabled { - let fsrs = FSRS::new(Some(&config.inner.fsrs_weights))?; + let fsrs = FSRS::new(Some(config.fsrs_params()))?; if card.memory_state.is_none() && card.ctype != CardType::New { // Card has been moved or imported into an FSRS deck after weights were set, // and will need its initial memory state to be calculated based on review diff --git a/rslib/src/scheduler/fsrs/memory_state.rs b/rslib/src/scheduler/fsrs/memory_state.rs index 8dec27ba8..d6836986d 100644 --- a/rslib/src/scheduler/fsrs/memory_state.rs +++ b/rslib/src/scheduler/fsrs/memory_state.rs @@ -154,7 +154,7 @@ impl Collection { .or_not_found(conf_id)?; let desired_retention = config.inner.desired_retention; let historical_retention = config.inner.historical_retention; - let fsrs = FSRS::new(Some(&config.inner.fsrs_weights))?; + let fsrs = FSRS::new(Some(config.fsrs_params()))?; let revlog = self.revlog_for_srs(SearchNode::CardIds(card.id.to_string()))?; let item = single_card_revlog_to_item( &fsrs, diff --git a/rslib/src/stats/card.rs b/rslib/src/stats/card.rs index b5da86d2b..ad713c813 100644 --- a/rslib/src/stats/card.rs +++ b/rslib/src/stats/card.rs @@ -130,7 +130,7 @@ impl Collection { .get_deck_config(conf_id)? .or_not_found(conf_id)?; let historical_retention = config.inner.historical_retention; - let fsrs = FSRS::new(Some(&config.inner.fsrs_weights))?; + let fsrs = FSRS::new(Some(config.fsrs_params()))?; let next_day_at = self.timing_today()?.next_day_at; let ignore_before = ignore_revlogs_before_ms_from_config(&config)?; diff --git a/ts/routes/deck-options/FsrsOptions.svelte b/ts/routes/deck-options/FsrsOptions.svelte index 2cef1537f..aa4d0aae6 100644 --- a/ts/routes/deck-options/FsrsOptions.svelte +++ b/ts/routes/deck-options/FsrsOptions.svelte @@ -26,7 +26,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import SwitchRow from "$lib/components/SwitchRow.svelte"; import GlobalLabel from "./GlobalLabel.svelte"; - import type { DeckOptionsState } from "./lib"; + import { fsrsParams, type DeckOptionsState } from "./lib"; import SpinBoxFloatRow from "./SpinBoxFloatRow.svelte"; import SpinBoxRow from "./SpinBoxRow.svelte"; import Warning from "./Warning.svelte"; @@ -82,7 +82,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } const simulateFsrsRequest = new SimulateFsrsReviewRequest({ - weights: $config.fsrsWeights, + weights: fsrsParams($config), desiredRetention: $config.desiredRetention, deckSize: 0, daysToSimulate: 365, @@ -137,26 +137,28 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html try { await runWithBackendProgress( async () => { + const params = fsrsParams($config); const resp = await computeFsrsWeights({ search: $config.weightSearch ? $config.weightSearch : defaultWeightSearch, ignoreRevlogsBeforeMs: getIgnoreRevlogsBeforeMs(), - currentWeights: $config.fsrsWeights, + currentWeights: params, }); if ( - ($config.fsrsWeights.length && - $config.fsrsWeights.every( + (params.length && + params.every( (n, i) => n.toFixed(4) === resp.weights[i].toFixed(4), )) || resp.weights.length === 0 ) { setTimeout(() => alert(tr.deckConfigFsrsParamsOptimal()), 100); + } else { + $config.fsrsParams5 = resp.weights; } if (computeWeightsProgress) { computeWeightsProgress.current = computeWeightsProgress.total; } - $config.fsrsWeights = resp.weights; }, (progress) => { if (progress.value.case === "computeWeights") { @@ -187,7 +189,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html ? $config.weightSearch : defaultWeightSearch; const resp = await evaluateWeights({ - weights: $config.fsrsWeights, + weights: fsrsParams($config), search, ignoreRevlogsBeforeMs: getIgnoreRevlogsBeforeMs(), }); @@ -230,7 +232,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html await runWithBackendProgress( async () => { optimalRetentionRequest.maxInterval = $config.maximumReviewInterval; - optimalRetentionRequest.weights = $config.fsrsWeights; + optimalRetentionRequest.weights = fsrsParams($config); optimalRetentionRequest.search = `preset:"${state.getCurrentName()}" -is:suspended`; const resp = await computeOptimalRetention(optimalRetentionRequest); optimalRetention = resp.optimalRetention; @@ -311,7 +313,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html try { await runWithBackendProgress( async () => { - simulateFsrsRequest.weights = $config.fsrsWeights; + simulateFsrsRequest.weights = fsrsParams($config); simulateFsrsRequest.desiredRetention = $config.desiredRetention; simulateFsrsRequest.search = `preset:"${state.getCurrentName()}" -is:suspended`; simulateProgressString = "processing..."; @@ -360,9 +362,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
openHelpModal("modelWeights")}> {tr.deckConfigWeights()} diff --git a/ts/routes/deck-options/lib.ts b/ts/routes/deck-options/lib.ts index 0c57f2977..dce872bd9 100644 --- a/ts/routes/deck-options/lib.ts +++ b/ts/routes/deck-options/lib.ts @@ -415,3 +415,11 @@ export async function commitEditing(): Promise { } await tick(); } + +export function fsrsParams(config: DeckConfig_Config): number[] { + if (config.fsrsParams5) { + return config.fsrsParams5; + } else { + return config.fsrsParams4; + } +} From 6adbd922f7d68d4fa15fb9b408b5b44e78bc7bd8 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 21 Oct 2024 18:10:08 +1000 Subject: [PATCH 021/113] Rename remaining 'weights' references to 'params' --- proto/anki/collection.proto | 8 +- proto/anki/deck_config.proto | 4 +- proto/anki/scheduler.proto | 32 ++--- pylib/anki/_backend.py | 4 +- qt/aqt/mediasrv.py | 8 +- rslib/src/backend/error.rs | 2 +- rslib/src/deckconfig/mod.rs | 2 +- rslib/src/deckconfig/schema11.rs | 10 +- rslib/src/deckconfig/update.rs | 38 +++--- rslib/src/error/mod.rs | 4 +- rslib/src/progress.rs | 14 +- rslib/src/scheduler/answering/mod.rs | 4 +- rslib/src/scheduler/fsrs/error.rs | 4 +- rslib/src/scheduler/fsrs/memory_state.rs | 18 +-- rslib/src/scheduler/fsrs/mod.rs | 2 +- .../scheduler/fsrs/{weights.rs => params.rs} | 43 +++--- rslib/src/scheduler/fsrs/retention.rs | 2 +- rslib/src/scheduler/fsrs/simulator.rs | 2 +- rslib/src/scheduler/service/mod.rs | 41 +++--- rslib/src/scheduler/states/load_balancer.rs | 8 +- rslib/src/stats/card.rs | 2 +- ts/routes/deck-options/FsrsOptions.svelte | 128 +++++++++--------- .../deck-options/FsrsOptionsOuter.svelte | 2 +- ...WeightsInput.svelte => ParamsInput.svelte} | 4 +- ...sInputRow.svelte => ParamsInputRow.svelte} | 4 +- ...earchRow.svelte => ParamsSearchRow.svelte} | 0 ts/routes/deck-options/SaveButton.svelte | 4 +- 27 files changed, 194 insertions(+), 200 deletions(-) rename rslib/src/scheduler/fsrs/{weights.rs => params.rs} (95%) rename ts/routes/deck-options/{WeightsInput.svelte => ParamsInput.svelte} (85%) rename ts/routes/deck-options/{WeightsInputRow.svelte => ParamsInputRow.svelte} (84%) rename ts/routes/deck-options/{WeightsSearchRow.svelte => ParamsSearchRow.svelte} (100%) diff --git a/proto/anki/collection.proto b/proto/anki/collection.proto index c08c36e27..fea70a787 100644 --- a/proto/anki/collection.proto +++ b/proto/anki/collection.proto @@ -127,21 +127,21 @@ message Progress { DatabaseCheck database_check = 6; string importing = 7; string exporting = 8; - ComputeWeightsProgress compute_weights = 9; + ComputeParamsProgress compute_params = 9; ComputeRetentionProgress compute_retention = 10; ComputeMemoryProgress compute_memory = 11; } } -message ComputeWeightsProgress { +message ComputeParamsProgress { // Current iteration uint32 current = 1; // Total iterations uint32 total = 2; uint32 reviews = 3; - // Only used in 'compute all weights' case + // Only used in 'compute all params' case uint32 current_preset = 4; - // Only used in 'compute all weights' case + // Only used in 'compute all params' case uint32 total_presets = 5; } diff --git a/proto/anki/deck_config.proto b/proto/anki/deck_config.proto index 1ac48c969..c3fc5298b 100644 --- a/proto/anki/deck_config.proto +++ b/proto/anki/deck_config.proto @@ -165,7 +165,7 @@ message DeckConfig { // used for fsrs_reschedule in the past reserved 39; float historical_retention = 40; - string weight_search = 45; + string param_search = 45; bytes other = 255; } @@ -215,7 +215,7 @@ message DeckConfigsForUpdate { enum UpdateDeckConfigsMode { UPDATE_DECK_CONFIGS_MODE_NORMAL = 0; UPDATE_DECK_CONFIGS_MODE_APPLY_TO_CHILDREN = 1; - UPDATE_DECK_CONFIGS_MODE_COMPUTE_ALL_WEIGHTS = 2; + UPDATE_DECK_CONFIGS_MODE_COMPUTE_ALL_PARAMS = 2; } message UpdateDeckConfigsRequest { diff --git a/proto/anki/scheduler.proto b/proto/anki/scheduler.proto index e0e653082..947a7812c 100644 --- a/proto/anki/scheduler.proto +++ b/proto/anki/scheduler.proto @@ -45,15 +45,15 @@ service SchedulerService { rpc CustomStudyDefaults(CustomStudyDefaultsRequest) returns (CustomStudyDefaultsResponse); rpc RepositionDefaults(generic.Empty) returns (RepositionDefaultsResponse); - rpc ComputeFsrsWeights(ComputeFsrsWeightsRequest) - returns (ComputeFsrsWeightsResponse); + rpc ComputeFsrsParams(ComputeFsrsParamsRequest) + returns (ComputeFsrsParamsResponse); rpc GetOptimalRetentionParameters(GetOptimalRetentionParametersRequest) returns (GetOptimalRetentionParametersResponse); rpc ComputeOptimalRetention(ComputeOptimalRetentionRequest) returns (ComputeOptimalRetentionResponse); rpc SimulateFsrsReview(SimulateFsrsReviewRequest) returns (SimulateFsrsReviewResponse); - rpc EvaluateWeights(EvaluateWeightsRequest) returns (EvaluateWeightsResponse); + rpc EvaluateParams(EvaluateParamsRequest) returns (EvaluateParamsResponse); rpc ComputeMemoryState(cards.CardId) returns (ComputeMemoryStateResponse); // The number of days the calculated interval was fuzzed by on the previous // review (if any). Utilized by the FSRS add-on. @@ -63,8 +63,8 @@ service SchedulerService { // Implicitly includes any of the above methods that are not listed in the // backend service. service BackendSchedulerService { - rpc ComputeFsrsWeightsFromItems(ComputeFsrsWeightsFromItemsRequest) - returns (ComputeFsrsWeightsResponse); + rpc ComputeFsrsParamsFromItems(ComputeFsrsParamsFromItemsRequest) + returns (ComputeFsrsParamsResponse); // Generates parameters used for FSRS's scheduler benchmarks. rpc FsrsBenchmark(FsrsBenchmarkRequest) returns (FsrsBenchmarkResponse); // Used for exporting revlogs for algorithm research. @@ -341,19 +341,19 @@ message RepositionDefaultsResponse { bool shift = 2; } -message ComputeFsrsWeightsRequest { +message ComputeFsrsParamsRequest { /// The search used to gather cards for training string search = 1; - repeated float current_weights = 2; + repeated float current_params = 2; int64 ignore_revlogs_before_ms = 3; } -message ComputeFsrsWeightsResponse { - repeated float weights = 1; +message ComputeFsrsParamsResponse { + repeated float params = 1; uint32 fsrs_items = 2; } -message ComputeFsrsWeightsFromItemsRequest { +message ComputeFsrsParamsFromItemsRequest { repeated FsrsItem items = 1; } @@ -362,7 +362,7 @@ message FsrsBenchmarkRequest { } message FsrsBenchmarkResponse { - repeated float weights = 1; + repeated float params = 1; } message ExportDatasetRequest { @@ -380,7 +380,7 @@ message FsrsReview { } message SimulateFsrsReviewRequest { - repeated float weights = 1; + repeated float params = 1; float desired_retention = 2; uint32 deck_size = 3; uint32 days_to_simulate = 4; @@ -398,7 +398,7 @@ message SimulateFsrsReviewResponse { } message ComputeOptimalRetentionRequest { - repeated float weights = 1; + repeated float params = 1; uint32 days_to_simulate = 2; uint32 max_interval = 3; string search = 4; @@ -431,13 +431,13 @@ message GetOptimalRetentionParametersResponse { uint32 review_limit = 15; } -message EvaluateWeightsRequest { - repeated float weights = 1; +message EvaluateParamsRequest { + repeated float params = 1; string search = 2; int64 ignore_revlogs_before_ms = 3; } -message EvaluateWeightsResponse { +message EvaluateParamsResponse { float log_loss = 1; float rmse_bins = 2; } diff --git a/pylib/anki/_backend.py b/pylib/anki/_backend.py index c3ac2a114..a0d8f8949 100644 --- a/pylib/anki/_backend.py +++ b/pylib/anki/_backend.py @@ -149,8 +149,8 @@ class RustBackend(RustBackendGenerated): ) return self.format_timespan(seconds=seconds, context=context) - def compute_weights_from_items(self, items: Iterable[FsrsItem]) -> Sequence[float]: - return self.compute_fsrs_weights_from_items(items).weights + def compute_params_from_items(self, items: Iterable[FsrsItem]) -> Sequence[float]: + return self.compute_fsrs_params_from_items(items).params def benchmark(self, train_set: Iterable[FsrsItem]) -> Sequence[float]: return self.fsrs_benchmark(train_set=train_set) diff --git a/qt/aqt/mediasrv.py b/qt/aqt/mediasrv.py index 26e52f503..ca4f23503 100644 --- a/qt/aqt/mediasrv.py +++ b/qt/aqt/mediasrv.py @@ -457,8 +457,8 @@ def update_deck_configs() -> bytes: update.max = val.total_cards update.value = val.current_cards update.label = val.label - elif progress.HasField("compute_weights"): - val2 = progress.compute_weights + elif progress.HasField("compute_params"): + val2 = progress.compute_params # prevent an indeterminate progress bar from appearing at the start of each preset update.max = max(val2.total, 1) update.value = val2.current @@ -621,10 +621,10 @@ exposed_backend_list = [ "update_image_occlusion_note", "get_image_occlusion_fields", # SchedulerService - "compute_fsrs_weights", + "compute_fsrs_params", "compute_optimal_retention", "set_wants_abort", - "evaluate_weights", + "evaluate_params", "get_optimal_retention_parameters", "simulate_fsrs_review", ] diff --git a/rslib/src/backend/error.rs b/rslib/src/backend/error.rs index 9e23c47ce..270a2f703 100644 --- a/rslib/src/backend/error.rs +++ b/rslib/src/backend/error.rs @@ -42,7 +42,7 @@ impl AnkiError { AnkiError::InvalidId => Kind::InvalidInput, AnkiError::InvalidMethodIndex | AnkiError::InvalidServiceIndex - | AnkiError::FsrsWeightsInvalid + | AnkiError::FsrsParamsInvalid | AnkiError::FsrsUnableToDetermineDesiredRetention | AnkiError::FsrsInsufficientData => Kind::InvalidInput, #[cfg(windows)] diff --git a/rslib/src/deckconfig/mod.rs b/rslib/src/deckconfig/mod.rs index ea299da7b..21a75f521 100644 --- a/rslib/src/deckconfig/mod.rs +++ b/rslib/src/deckconfig/mod.rs @@ -79,7 +79,7 @@ const DEFAULT_DECK_CONFIG_INNER: DeckConfigInner = DeckConfigInner { desired_retention: 0.9, other: Vec::new(), historical_retention: 0.9, - weight_search: String::new(), + param_search: String::new(), ignore_revlogs_before_date: String::new(), easy_days_percentages: Vec::new(), }; diff --git a/rslib/src/deckconfig/schema11.rs b/rslib/src/deckconfig/schema11.rs index bde3f2234..73800f38e 100644 --- a/rslib/src/deckconfig/schema11.rs +++ b/rslib/src/deckconfig/schema11.rs @@ -94,8 +94,8 @@ pub struct DeckConfSchema11 { #[serde(default)] /// historical retention sm2_retention: f32, - #[serde(default)] - weight_search: String, + #[serde(default, rename = "weightSearch")] + param_search: String, #[serde(flatten)] other: HashMap, @@ -312,7 +312,7 @@ impl Default for DeckConfSchema11 { fsrs_params_5: vec![], desired_retention: 0.9, sm2_retention: 0.9, - weight_search: "".to_string(), + param_search: "".to_string(), ignore_revlogs_before_date: "".to_string(), easy_days_percentages: vec![1.0; 7], } @@ -395,7 +395,7 @@ impl From for DeckConfig { easy_days_percentages: c.easy_days_percentages, desired_retention: c.desired_retention, historical_retention: c.sm2_retention, - weight_search: c.weight_search, + param_search: c.param_search, other: other_bytes, }, } @@ -506,7 +506,7 @@ impl From for DeckConfSchema11 { fsrs_params_5: i.fsrs_params_5, desired_retention: i.desired_retention, sm2_retention: i.historical_retention, - weight_search: i.weight_search, + param_search: i.param_search, ignore_revlogs_before_date: i.ignore_revlogs_before_date, easy_days_percentages: i.easy_days_percentages, } diff --git a/rslib/src/deckconfig/update.rs b/rslib/src/deckconfig/update.rs index e931dad4a..f56d0bf47 100644 --- a/rslib/src/deckconfig/update.rs +++ b/rslib/src/deckconfig/update.rs @@ -21,7 +21,7 @@ use crate::decks::NormalDeck; use crate::prelude::*; use crate::scheduler::fsrs::memory_state::UpdateMemoryStateEntry; use crate::scheduler::fsrs::memory_state::UpdateMemoryStateRequest; -use crate::scheduler::fsrs::weights::ignore_revlogs_before_ms_from_config; +use crate::scheduler::fsrs::params::ignore_revlogs_before_ms_from_config; use crate::search::JoinSearches; use crate::search::Negated; use crate::search::SearchNode; @@ -159,8 +159,8 @@ impl Collection { configs_after_update.remove(dcid); } - if req.mode == UpdateDeckConfigsMode::ComputeAllWeights { - self.compute_all_weights(&mut req)?; + if req.mode == UpdateDeckConfigsMode::ComputeAllParams { + self.compute_all_params(&mut req)?; } // add/update provided configs @@ -207,13 +207,13 @@ impl Collection { if let Ok(normal) = deck.normal() { let deck_id = deck.id; - // previous order & weights + // previous order & params let previous_config_id = DeckConfigId(normal.config_id); let previous_config = configs_before_update.get(&previous_config_id); let previous_order = previous_config .map(|c| c.inner.new_card_insert_order()) .unwrap_or_default(); - let previous_weights = previous_config.map(|c| c.fsrs_params()); + let previous_params = previous_config.map(|c| c.fsrs_params()); let previous_retention = previous_config.map(|c| c.inner.desired_retention); // if a selected (sub)deck, or its old config was removed, update deck to point @@ -239,11 +239,11 @@ impl Collection { self.sort_deck(deck_id, current_order, usn)?; } - // if weights differ, memory state needs to be recomputed - let current_weights = current_config.map(|c| c.fsrs_params()); + // if params differ, memory state needs to be recomputed + let current_params = current_config.map(|c| c.fsrs_params()); let current_retention = current_config.map(|c| c.inner.desired_retention); if fsrs_toggled - || previous_weights != current_weights + || previous_params != current_params || previous_retention != current_retention { decks_needing_memory_recompute @@ -261,10 +261,10 @@ impl Collection { .into_iter() .map(|(conf_id, search)| { let config = configs_after_update.get(&conf_id); - let weights = config.and_then(|c| { + let params = config.and_then(|c| { if req.fsrs { Some(UpdateMemoryStateRequest { - weights: c.fsrs_params().clone(), + params: c.fsrs_params().clone(), desired_retention: c.inner.desired_retention, max_interval: c.inner.maximum_review_interval, reschedule: req.fsrs_reschedule, @@ -275,7 +275,7 @@ impl Collection { } }); Ok(UpdateMemoryStateEntry { - req: weights, + req: params, search: SearchNode::DeckIdsWithoutChildren(comma_separated_ids(&search)), ignore_before: config .map(ignore_revlogs_before_ms_from_config) @@ -329,7 +329,7 @@ impl Collection { } Ok(()) } - fn compute_all_weights(&mut self, req: &mut UpdateDeckConfigsRequest) -> Result<()> { + fn compute_all_params(&mut self, req: &mut UpdateDeckConfigsRequest) -> Result<()> { require!(req.fsrs, "FSRS must be enabled"); // frontend didn't include any unmodified deck configs, so we need to fill them @@ -344,28 +344,28 @@ impl Collection { // other parts of the code expect the currently-selected preset to come last req.configs.push(previous_last); - // calculate and apply weights to each preset + // calculate and apply params to each preset let config_len = req.configs.len() as u32; for (idx, config) in req.configs.iter_mut().enumerate() { - let search = if config.inner.weight_search.trim().is_empty() { + let search = if config.inner.param_search.trim().is_empty() { SearchNode::Preset(config.name.clone()) .and(SearchNode::State(StateKind::Suspended).negated()) .try_into_search()? .to_string() } else { - config.inner.weight_search.clone() + config.inner.param_search.clone() }; let ignore_revlogs_before_ms = ignore_revlogs_before_ms_from_config(config)?; - match self.compute_weights( + match self.compute_params( &search, ignore_revlogs_before_ms, idx as u32 + 1, config_len, config.fsrs_params(), ) { - Ok(weights) => { - println!("{}: {:?}", config.name, weights.weights); - config.inner.fsrs_params_5 = weights.weights; + Ok(params) => { + println!("{}: {:?}", config.name, params.params); + config.inner.fsrs_params_5 = params.params; } Err(AnkiError::Interrupted) => return Err(AnkiError::Interrupted), Err(err) => { diff --git a/rslib/src/error/mod.rs b/rslib/src/error/mod.rs index 416690e8b..72ba05baf 100644 --- a/rslib/src/error/mod.rs +++ b/rslib/src/error/mod.rs @@ -113,7 +113,7 @@ pub enum AnkiError { }, InvalidMethodIndex, InvalidServiceIndex, - FsrsWeightsInvalid, + FsrsParamsInvalid, /// Returned by fsrs-rs; may happen even if 400+ reviews FsrsInsufficientData, /// Generated by our backend if count < 400 @@ -181,7 +181,7 @@ impl AnkiError { AnkiError::FsrsInsufficientReviews { count } => { tr.deck_config_must_have_400_reviews(*count).into() } - AnkiError::FsrsWeightsInvalid => tr.deck_config_invalid_parameters().into(), + AnkiError::FsrsParamsInvalid => tr.deck_config_invalid_parameters().into(), AnkiError::SchedulerUpgradeRequired => { tr.scheduling_update_required().replace("V2", "v3") } diff --git a/rslib/src/progress.rs b/rslib/src/progress.rs index c1412251f..a404808bf 100644 --- a/rslib/src/progress.rs +++ b/rslib/src/progress.rs @@ -15,8 +15,8 @@ use crate::import_export::ExportProgress; use crate::import_export::ImportProgress; use crate::prelude::Collection; use crate::scheduler::fsrs::memory_state::ComputeMemoryProgress; +use crate::scheduler::fsrs::params::ComputeParamsProgress; use crate::scheduler::fsrs::retention::ComputeRetentionProgress; -use crate::scheduler::fsrs::weights::ComputeWeightsProgress; use crate::sync::collection::normal::NormalSyncProgress; use crate::sync::collection::progress::FullSyncProgress; use crate::sync::collection::progress::SyncStage; @@ -131,7 +131,7 @@ pub enum Progress { DatabaseCheck(DatabaseCheckProgress), Import(ImportProgress), Export(ExportProgress), - ComputeWeights(ComputeWeightsProgress), + ComputeParams(ComputeParamsProgress), ComputeRetention(ComputeRetentionProgress), ComputeMemory(ComputeMemoryProgress), } @@ -209,8 +209,8 @@ pub(crate) fn progress_to_proto( } .into(), ), - Progress::ComputeWeights(progress) => { - Value::ComputeWeights(anki_proto::collection::ComputeWeightsProgress { + Progress::ComputeParams(progress) => { + Value::ComputeParams(anki_proto::collection::ComputeParamsProgress { current: progress.current_iteration, total: progress.total_iterations, reviews: progress.reviews, @@ -296,9 +296,9 @@ impl From for Progress { } } -impl From for Progress { - fn from(p: ComputeWeightsProgress) -> Self { - Progress::ComputeWeights(p) +impl From for Progress { + fn from(p: ComputeParamsProgress) -> Self { + Progress::ComputeParams(p) } } diff --git a/rslib/src/scheduler/answering/mod.rs b/rslib/src/scheduler/answering/mod.rs index 9458e7559..61ff13fbb 100644 --- a/rslib/src/scheduler/answering/mod.rs +++ b/rslib/src/scheduler/answering/mod.rs @@ -14,7 +14,7 @@ use rand::prelude::*; use rand::rngs::StdRng; use revlog::RevlogEntryPartial; -use super::fsrs::weights::ignore_revlogs_before_ms_from_config; +use super::fsrs::params::ignore_revlogs_before_ms_from_config; use super::queue::BuryMode; use super::states::load_balancer::LoadBalancerContext; use super::states::steps::LearningSteps; @@ -433,7 +433,7 @@ impl Collection { let fsrs_next_states = if fsrs_enabled { let fsrs = FSRS::new(Some(config.fsrs_params()))?; if card.memory_state.is_none() && card.ctype != CardType::New { - // Card has been moved or imported into an FSRS deck after weights were set, + // Card has been moved or imported into an FSRS deck after params were set, // and will need its initial memory state to be calculated based on review // history. let revlog = self.revlog_for_srs(SearchNode::CardIds(card.id.to_string()))?; diff --git a/rslib/src/scheduler/fsrs/error.rs b/rslib/src/scheduler/fsrs/error.rs index 5c9f030ee..d5b596a36 100644 --- a/rslib/src/scheduler/fsrs/error.rs +++ b/rslib/src/scheduler/fsrs/error.rs @@ -12,10 +12,10 @@ impl From for AnkiError { FSRSError::NotEnoughData => AnkiError::FsrsInsufficientData, FSRSError::OptimalNotFound => AnkiError::FsrsUnableToDetermineDesiredRetention, FSRSError::Interrupted => AnkiError::Interrupted, - FSRSError::InvalidParameters => AnkiError::FsrsWeightsInvalid, + FSRSError::InvalidParameters => AnkiError::FsrsParamsInvalid, FSRSError::InvalidInput => AnkiError::InvalidInput { source: InvalidInputError { - message: "invalid weights provided".to_string(), + message: "invalid params provided".to_string(), source: None, backtrace: None, }, diff --git a/rslib/src/scheduler/fsrs/memory_state.rs b/rslib/src/scheduler/fsrs/memory_state.rs index d6836986d..decc9777b 100644 --- a/rslib/src/scheduler/fsrs/memory_state.rs +++ b/rslib/src/scheduler/fsrs/memory_state.rs @@ -9,13 +9,13 @@ use fsrs::MemoryState; use fsrs::FSRS; use itertools::Itertools; -use super::weights::ignore_revlogs_before_ms_from_config; +use super::params::ignore_revlogs_before_ms_from_config; use crate::card::CardType; use crate::prelude::*; use crate::revlog::RevlogEntry; use crate::revlog::RevlogReviewKind; -use crate::scheduler::fsrs::weights::single_card_revlog_to_items; -use crate::scheduler::fsrs::weights::Weights; +use crate::scheduler::fsrs::params::single_card_revlog_to_items; +use crate::scheduler::fsrs::params::Params; use crate::scheduler::states::fuzz::with_review_fuzz; use crate::search::Negated; use crate::search::SearchNode; @@ -29,7 +29,7 @@ pub struct ComputeMemoryProgress { #[derive(Debug)] pub(crate) struct UpdateMemoryStateRequest { - pub weights: Weights, + pub params: Params, pub desired_retention: f32, pub historical_retention: f32, pub max_interval: u32, @@ -43,10 +43,10 @@ pub(crate) struct UpdateMemoryStateEntry { } impl Collection { - /// For each provided set of weights, locate cards with the provided search, + /// For each provided set of params, locate cards with the provided search, /// and update their memory state. /// Should be called inside a transaction. - /// If Weights are None, it means the user disabled FSRS, and the existing + /// If Params are None, it means the user disabled FSRS, and the existing /// memory state should be removed. pub(crate) fn update_memory_state( &mut self, @@ -69,7 +69,7 @@ impl Collection { } else { None }; - let fsrs = FSRS::new(req.as_ref().map(|w| &w.weights[..]).or(Some([].as_slice())))?; + let fsrs = FSRS::new(req.as_ref().map(|w| &w.params[..]).or(Some([].as_slice())))?; let historical_retention = req.as_ref().map(|w| w.historical_retention); let items = fsrs_items_for_memory_state( &fsrs, @@ -337,8 +337,8 @@ mod tests { use super::*; use crate::card::FsrsMemoryState; use crate::revlog::RevlogReviewKind; - use crate::scheduler::fsrs::weights::tests::convert; - use crate::scheduler::fsrs::weights::tests::revlog; + use crate::scheduler::fsrs::params::tests::convert; + use crate::scheduler::fsrs::params::tests::revlog; /// Floating point precision can vary between platforms, and each FSRS /// update tends to result in small changes to these numbers, so we diff --git a/rslib/src/scheduler/fsrs/mod.rs b/rslib/src/scheduler/fsrs/mod.rs index 8a0bd51fe..aa324dddb 100644 --- a/rslib/src/scheduler/fsrs/mod.rs +++ b/rslib/src/scheduler/fsrs/mod.rs @@ -2,7 +2,7 @@ // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html mod error; pub mod memory_state; +pub mod params; pub mod retention; pub mod simulator; pub mod try_collect; -pub mod weights; diff --git a/rslib/src/scheduler/fsrs/weights.rs b/rslib/src/scheduler/fsrs/params.rs similarity index 95% rename from rslib/src/scheduler/fsrs/weights.rs rename to rslib/src/scheduler/fsrs/params.rs index 0c370fbe0..1bedf4ffc 100644 --- a/rslib/src/scheduler/fsrs/weights.rs +++ b/rslib/src/scheduler/fsrs/params.rs @@ -7,7 +7,7 @@ use std::thread; use std::time::Duration; use anki_io::write_file; -use anki_proto::scheduler::ComputeFsrsWeightsResponse; +use anki_proto::scheduler::ComputeFsrsParamsResponse; use anki_proto::stats::revlog_entry; use anki_proto::stats::Dataset; use anki_proto::stats::DeckEntry; @@ -29,7 +29,7 @@ use crate::search::Node; use crate::search::SearchNode; use crate::search::SortMode; -pub(crate) type Weights = Vec; +pub(crate) type Params = Vec; fn ignore_revlogs_before_date_to_ms( ignore_revlogs_before_date: &String, @@ -53,15 +53,15 @@ impl Collection { /// Note this does not return an error if there are less than 400 items - /// the caller should instead check the fsrs_items count in the return /// value. - pub fn compute_weights( + pub fn compute_params( &mut self, search: &str, ignore_revlogs_before: TimestampMillis, current_preset: u32, total_presets: u32, - current_weights: &Weights, - ) -> Result { - let mut anki_progress = self.new_progress_handler::(); + current_params: &Params, + ) -> Result { + let mut anki_progress = self.new_progress_handler::(); let timing = self.timing_today()?; let revlogs = self.revlog_for_srs(search)?; let (items, review_count) = @@ -69,8 +69,8 @@ impl Collection { let fsrs_items = items.len() as u32; if fsrs_items == 0 { - return Ok(ComputeFsrsWeightsResponse { - weights: current_weights.to_vec(), + return Ok(ComputeFsrsParamsResponse { + params: current_params.to_vec(), fsrs_items, }); } @@ -97,20 +97,17 @@ impl Collection { } } }); - let mut weights = FSRS::new(None)?.compute_parameters(items.clone(), Some(progress2))?; - if let Ok(fsrs) = FSRS::new(Some(current_weights)) { + let mut params = FSRS::new(None)?.compute_parameters(items.clone(), Some(progress2))?; + if let Ok(fsrs) = FSRS::new(Some(current_params)) { let current_rmse = fsrs.evaluate(items.clone(), |_| true)?.rmse_bins; - let optimized_fsrs = FSRS::new(Some(&weights))?; + let optimized_fsrs = FSRS::new(Some(¶ms))?; let optimized_rmse = optimized_fsrs.evaluate(items.clone(), |_| true)?.rmse_bins; if current_rmse <= optimized_rmse { - weights = current_weights.to_vec(); + params = current_params.to_vec(); } } - Ok(ComputeFsrsWeightsResponse { - weights, - fsrs_items, - }) + Ok(ComputeFsrsParamsResponse { params, fsrs_items }) } pub(crate) fn revlog_for_srs( @@ -180,14 +177,14 @@ impl Collection { Ok(()) } - pub fn evaluate_weights( + pub fn evaluate_params( &mut self, - weights: &Weights, + params: &Params, search: &str, ignore_revlogs_before: TimestampMillis, ) -> Result { let timing = self.timing_today()?; - let mut anki_progress = self.new_progress_handler::(); + let mut anki_progress = self.new_progress_handler::(); let guard = self.search_cards_into_table(search, SortMode::NoOrder)?; let revlogs: Vec = guard .col @@ -196,7 +193,7 @@ impl Collection { let (items, review_count) = fsrs_items_for_training(revlogs, timing.next_day_at, ignore_revlogs_before); anki_progress.state.reviews = review_count as u32; - let fsrs = FSRS::new(Some(weights))?; + let fsrs = FSRS::new(Some(params))?; Ok(fsrs.evaluate(items, |ip| { anki_progress .update(false, |p| { @@ -209,13 +206,13 @@ impl Collection { } #[derive(Default, Clone, Copy, Debug)] -pub struct ComputeWeightsProgress { +pub struct ComputeParamsProgress { pub current_iteration: u32, pub total_iterations: u32, pub reviews: u32, - /// Only used in 'compute all weights' case + /// Only used in 'compute all params' case pub current_preset: u32, - /// Only used in 'compute all weights' case + /// Only used in 'compute all params' case pub total_presets: u32, } diff --git a/rslib/src/scheduler/fsrs/retention.rs b/rslib/src/scheduler/fsrs/retention.rs index f2951f2dc..a408b6013 100644 --- a/rslib/src/scheduler/fsrs/retention.rs +++ b/rslib/src/scheduler/fsrs/retention.rs @@ -54,7 +54,7 @@ impl Collection { learn_limit, review_limit: usize::MAX, }, - &req.weights, + &req.params, |ip| { anki_progress .update(false, |p| { diff --git a/rslib/src/scheduler/fsrs/simulator.rs b/rslib/src/scheduler/fsrs/simulator.rs index 9b1c0d072..70a6d9001 100644 --- a/rslib/src/scheduler/fsrs/simulator.rs +++ b/rslib/src/scheduler/fsrs/simulator.rs @@ -54,7 +54,7 @@ impl Collection { daily_time_cost, ) = simulate( &config, - &req.weights, + &req.params, req.desired_retention, None, Some(converted_cards), diff --git a/rslib/src/scheduler/service/mod.rs b/rslib/src/scheduler/service/mod.rs index aa71d4829..59a9aa503 100644 --- a/rslib/src/scheduler/service/mod.rs +++ b/rslib/src/scheduler/service/mod.rs @@ -7,7 +7,7 @@ mod states; use anki_proto::cards; use anki_proto::generic; use anki_proto::scheduler; -use anki_proto::scheduler::ComputeFsrsWeightsResponse; +use anki_proto::scheduler::ComputeFsrsParamsResponse; use anki_proto::scheduler::ComputeMemoryStateResponse; use anki_proto::scheduler::ComputeOptimalRetentionRequest; use anki_proto::scheduler::ComputeOptimalRetentionResponse; @@ -254,16 +254,16 @@ impl crate::services::SchedulerService for Collection { self.custom_study_defaults(input.deck_id.into()) } - fn compute_fsrs_weights( + fn compute_fsrs_params( &mut self, - input: scheduler::ComputeFsrsWeightsRequest, - ) -> Result { - self.compute_weights( + input: scheduler::ComputeFsrsParamsRequest, + ) -> Result { + self.compute_params( &input.search, input.ignore_revlogs_before_ms.into(), 1, 1, - &input.current_weights, + &input.current_params, ) } @@ -283,16 +283,16 @@ impl crate::services::SchedulerService for Collection { }) } - fn evaluate_weights( + fn evaluate_params( &mut self, - input: scheduler::EvaluateWeightsRequest, - ) -> Result { - let ret = self.evaluate_weights( - &input.weights, + input: scheduler::EvaluateParamsRequest, + ) -> Result { + let ret = self.evaluate_params( + &input.params, &input.search, input.ignore_revlogs_before_ms.into(), )?; - Ok(scheduler::EvaluateWeightsResponse { + Ok(scheduler::EvaluateParamsResponse { log_loss: ret.log_loss, rmse_bins: ret.rmse_bins, }) @@ -339,20 +339,17 @@ impl crate::services::SchedulerService for Collection { } impl crate::services::BackendSchedulerService for Backend { - fn compute_fsrs_weights_from_items( + fn compute_fsrs_params_from_items( &self, - req: scheduler::ComputeFsrsWeightsFromItemsRequest, - ) -> Result { + req: scheduler::ComputeFsrsParamsFromItemsRequest, + ) -> Result { let fsrs = FSRS::new(None)?; let fsrs_items = req.items.len() as u32; - let weights = fsrs.compute_parameters( + let params = fsrs.compute_parameters( req.items.into_iter().map(fsrs_item_proto_to_fsrs).collect(), None, )?; - Ok(ComputeFsrsWeightsResponse { - weights, - fsrs_items, - }) + Ok(ComputeFsrsParamsResponse { params, fsrs_items }) } fn fsrs_benchmark( @@ -365,8 +362,8 @@ impl crate::services::BackendSchedulerService for Backend { .into_iter() .map(fsrs_item_proto_to_fsrs) .collect(); - let weights = fsrs.benchmark(train_set); - Ok(FsrsBenchmarkResponse { weights }) + let params = fsrs.benchmark(train_set); + Ok(FsrsBenchmarkResponse { params }) } fn export_dataset(&self, req: scheduler::ExportDatasetRequest) -> Result<()> { diff --git a/rslib/src/scheduler/states/load_balancer.rs b/rslib/src/scheduler/states/load_balancer.rs index 5ba2103e1..6cd59d538 100644 --- a/rslib/src/scheduler/states/load_balancer.rs +++ b/rslib/src/scheduler/states/load_balancer.rs @@ -226,8 +226,8 @@ impl LoadBalancer { .collect::>(); let expected_distribution = check_review_distribution(&review_counts, &percentages); - // calculate weights for each day - let intervals_and_weights = interval_days + // calculate params for each day + let intervals_and_params = interval_days .iter() .enumerate() .map(|(interval_index, interval_day)| { @@ -262,10 +262,10 @@ impl LoadBalancer { let mut rng = StdRng::seed_from_u64(fuzz_seed?); let weighted_intervals = - WeightedIndex::new(intervals_and_weights.iter().map(|k| k.1)).ok()?; + WeightedIndex::new(intervals_and_params.iter().map(|k| k.1)).ok()?; let selected_interval_index = weighted_intervals.sample(&mut rng); - Some(intervals_and_weights[selected_interval_index].0) + Some(intervals_and_params[selected_interval_index].0) } pub fn add_card(&mut self, cid: CardId, nid: NoteId, dcid: DeckConfigId, interval: u32) { diff --git a/rslib/src/stats/card.rs b/rslib/src/stats/card.rs index ad713c813..1b2b1d376 100644 --- a/rslib/src/stats/card.rs +++ b/rslib/src/stats/card.rs @@ -7,7 +7,7 @@ use crate::card::CardType; use crate::prelude::*; use crate::revlog::RevlogEntry; use crate::scheduler::fsrs::memory_state::single_card_revlog_to_item; -use crate::scheduler::fsrs::weights::ignore_revlogs_before_ms_from_config; +use crate::scheduler::fsrs::params::ignore_revlogs_before_ms_from_config; use crate::scheduler::timing::is_unix_epoch_timestamp; impl Collection { diff --git a/ts/routes/deck-options/FsrsOptions.svelte b/ts/routes/deck-options/FsrsOptions.svelte index aa4d0aae6..42a5e891d 100644 --- a/ts/routes/deck-options/FsrsOptions.svelte +++ b/ts/routes/deck-options/FsrsOptions.svelte @@ -5,7 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html diff --git a/ts/routes/deck-options/DisplayOrder.svelte b/ts/routes/deck-options/DisplayOrder.svelte index 5ea8d1d89..88fc97fc3 100644 --- a/ts/routes/deck-options/DisplayOrder.svelte +++ b/ts/routes/deck-options/DisplayOrder.svelte @@ -38,6 +38,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html const currentDeck = "\n\n" + tr.deckConfigDisplayOrderWillUseCurrentDeck(); let disabledNewSortOrders: number[] = []; + // svelte-ignore reactive_declaration_non_reactive_property $: { switch ($config.newCardGatherPriority) { case GatherOrder.RANDOM_NOTES: diff --git a/ts/routes/deck-options/NewOptions.svelte b/ts/routes/deck-options/NewOptions.svelte index 74463b490..e5417f1b7 100644 --- a/ts/routes/deck-options/NewOptions.svelte +++ b/ts/routes/deck-options/NewOptions.svelte @@ -51,6 +51,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html ? tr.deckConfigGoodAboveEasy() : ""; + // svelte-ignore reactive_declaration_non_reactive_property $: insertionOrderRandom = $config.newCardInsertOrder == DeckConfig_Config_NewCardInsertOrder.RANDOM ? tr.deckConfigNewInsertionOrderRandomWithV3() diff --git a/ts/routes/graphs/CalendarGraph.svelte b/ts/routes/graphs/CalendarGraph.svelte index a8907ee00..009ed0c88 100644 --- a/ts/routes/graphs/CalendarGraph.svelte +++ b/ts/routes/graphs/CalendarGraph.svelte @@ -49,6 +49,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html ); } + // svelte-ignore reactive_declaration_non_reactive_property $: { if (revlogRange < RevlogRange.Year) { minYear = maxYear; diff --git a/ts/routes/graphs/RangeBox.svelte b/ts/routes/graphs/RangeBox.svelte index ac74703f9..6be754fe7 100644 --- a/ts/routes/graphs/RangeBox.svelte +++ b/ts/routes/graphs/RangeBox.svelte @@ -44,6 +44,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } } + // svelte-ignore reactive_declaration_non_reactive_property $: { switch (revlogRange as RevlogRange) { case RevlogRange.Year: diff --git a/yarn.lock b/yarn.lock index 85d82cc20..a0be1ad8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@ampproject/remapping@^2.2.1": +"@ampproject/remapping@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== @@ -32,45 +32,45 @@ "@typescript/vfs" "^1.4.0" typescript "4.5.2" -"@dprint/darwin-arm64@0.47.2": - version "0.47.2" - resolved "https://registry.yarnpkg.com/@dprint/darwin-arm64/-/darwin-arm64-0.47.2.tgz#dea8bfa146159e565e510266a2f1d7ebd2676090" - integrity sha512-mVPFBJsXxGDKHHCAY8wbqOyS4028g1bN15H9tivCnPAjwaZhkUimZHXWejXADjhGn+Xm2SlakugY9PY/68pH3Q== +"@dprint/darwin-arm64@0.47.4": + version "0.47.4" + resolved "https://registry.yarnpkg.com/@dprint/darwin-arm64/-/darwin-arm64-0.47.4.tgz#bf2088f71c968447a06e68469bc5eb03c3a42c61" + integrity sha512-TZKDhU3YfPwij66sMAnFjyqACwz0jrJoVLV1x00IR7CluWBas2hOBWQd2UhhncF+llnltQ8U0+m7lU7jrBHEew== -"@dprint/darwin-x64@0.47.2": - version "0.47.2" - resolved "https://registry.yarnpkg.com/@dprint/darwin-x64/-/darwin-x64-0.47.2.tgz#9e03a7ebb1a38ffcd46fbade96e98e8326d4c77c" - integrity sha512-T7wzlc+rBV+6BRRiBjoqoy5Hj4TR2Nv2p2s9+ycyPGs10Kj/JXOWD8dnEHeBgUr2r4qe/ZdcxmsFQ5Hf2n0WuA== +"@dprint/darwin-x64@0.47.4": + version "0.47.4" + resolved "https://registry.yarnpkg.com/@dprint/darwin-x64/-/darwin-x64-0.47.4.tgz#93fc5654d0b515ab00aff7972be80fb6d92a4000" + integrity sha512-6C0p8x9lN8Y81OZHQWCFCn7oE7NDFkeARvG1TIgO9EouKWoa9vNUNoxA5DNhDhlFPSejWfxiwLXn0ZKrPEnCHQ== -"@dprint/linux-arm64-glibc@0.47.2": - version "0.47.2" - resolved "https://registry.yarnpkg.com/@dprint/linux-arm64-glibc/-/linux-arm64-glibc-0.47.2.tgz#7d6c70b1c097d8dd8756cb4cdff40afdde4d42f3" - integrity sha512-B0m1vT5LdVtrNOVdkqpLPrSxuCD+l5bTIgRzPaDoIB1ChWQkler9IlX8C+RStpujjPj6SYvwo5vTzjQSvRdQkA== +"@dprint/linux-arm64-glibc@0.47.4": + version "0.47.4" + resolved "https://registry.yarnpkg.com/@dprint/linux-arm64-glibc/-/linux-arm64-glibc-0.47.4.tgz#b25cd6667b9a4789cfa5474e695fae9d7c79a0f6" + integrity sha512-eQk6DCHNKtvZMmpaBKnmJABUx5uKR3gWR+2I7XCCGaIS5VCM4RV2bA7x9gCUAUaLzmvm17rragHnSkzX+672oQ== -"@dprint/linux-arm64-musl@0.47.2": - version "0.47.2" - resolved "https://registry.yarnpkg.com/@dprint/linux-arm64-musl/-/linux-arm64-musl-0.47.2.tgz#76158f3400848d6d00023559c7b1fbf1cf1198c9" - integrity sha512-zID6wZZqpg2/Q2Us+ERQkbhLwlW3p3xaeEr00MPf49bpydmEjMiPuSjWPkNv+slQSIyIsVovOxF4lbNZjsdtvw== +"@dprint/linux-arm64-musl@0.47.4": + version "0.47.4" + resolved "https://registry.yarnpkg.com/@dprint/linux-arm64-musl/-/linux-arm64-musl-0.47.4.tgz#e0ace501bc638da9af2472b59adc1841fbe6e9ef" + integrity sha512-bHnohA+pnU1ybIYNcw28Z761OXt9q149Izo30gwi2GgY6JJR+3h9Nl4NAsvIPzd0kwL1Unz1ZFGcVMp+wI82Fg== -"@dprint/linux-x64-glibc@0.47.2": - version "0.47.2" - resolved "https://registry.yarnpkg.com/@dprint/linux-x64-glibc/-/linux-x64-glibc-0.47.2.tgz#1c30261e7a085bcbd6d673c7ac4064a4e50c1a02" - integrity sha512-rB3WXMdINnRd33DItIp7mObS7dzHW90ZzeJSsoKJLPp+Z7wXjjb27UUowfqVI4baa/1pd7sdbX54DPohMtfu/A== +"@dprint/linux-x64-glibc@0.47.4": + version "0.47.4" + resolved "https://registry.yarnpkg.com/@dprint/linux-x64-glibc/-/linux-x64-glibc-0.47.4.tgz#bc79f9600d09b8177971a4efcf6f2aaab455eb68" + integrity sha512-hmOA/edKJErs0yw8hHubzBjGuYasvWNRvv3y7FBl5Ega9nq7hCfUhupTs/4g0lTWabcdU2xFA8xVJnaT95uOQw== -"@dprint/linux-x64-musl@0.47.2": - version "0.47.2" - resolved "https://registry.yarnpkg.com/@dprint/linux-x64-musl/-/linux-x64-musl-0.47.2.tgz#27d50baca893bbaa8d5ff6448621a1d68d5eba1b" - integrity sha512-E0+TNbzYdTXJ/jCVjUctVxkda/faw++aDQLfyWGcmdMJnbM7NZz+W4fUpDXzMPsjy+zTWxXcPK7/q2DZz2gnbg== +"@dprint/linux-x64-musl@0.47.4": + version "0.47.4" + resolved "https://registry.yarnpkg.com/@dprint/linux-x64-musl/-/linux-x64-musl-0.47.4.tgz#5d9c514ac1391bbf0bd2affadcb0f185bedfa772" + integrity sha512-1gBQ7uyMw+Ix8uJd1WmdCXRm53VpIjZsQraPZUr+uOtUitZFMFK+dw1bNFpjxGTalahFDHp3XEnTQxLlw2MD1A== -"@dprint/win32-arm64@0.47.2": - version "0.47.2" - resolved "https://registry.yarnpkg.com/@dprint/win32-arm64/-/win32-arm64-0.47.2.tgz#eb7eb2b4acd17d8221ae85c835c80aa1b6b3110c" - integrity sha512-K1EieTCFjfOCmyIhw9zFSduE6qVCNHEveupqZEfbSkVGw5T9MJQ1I9+n7MDb3RIDYEUk0enJ58/w82q8oDKCyA== +"@dprint/win32-arm64@0.47.4": + version "0.47.4" + resolved "https://registry.yarnpkg.com/@dprint/win32-arm64/-/win32-arm64-0.47.4.tgz#315516e5c4497c41f60d772ec5624d92a78e8609" + integrity sha512-05UJS2ggH65BmdJGDkSaUF61CJyau65oqSlpPydmu+RKK5/sEUj/b6A0QCpR57fLh0Q3e9CqkwzfYf4qUJ55ew== -"@dprint/win32-x64@0.47.2": - version "0.47.2" - resolved "https://registry.yarnpkg.com/@dprint/win32-x64/-/win32-x64-0.47.2.tgz#117c4b22de19dd11991851f27424ccc332d2266a" - integrity sha512-LhizWr8VrhHvq4ump8HwOERyFmdLiE8C6A42QSntGXzKdaa2nEOq20x/o56ZIiDcesiV+1TmosMKimPcOZHa+Q== +"@dprint/win32-x64@0.47.4": + version "0.47.4" + resolved "https://registry.yarnpkg.com/@dprint/win32-x64/-/win32-x64-0.47.4.tgz#ccac38bf7221a4c3cd50cc1f1947596605a940f3" + integrity sha512-aQtujd8xtJ84I90pLCTwAl4SvkAhhQPRfDE5BkZYnK+5iMkigA1eQd7UCqAEUKeCJrO5N41OXaEWgmOhBctvJg== "@esbuild/aix-ppc64@0.21.5": version "0.21.5" @@ -298,16 +298,16 @@ integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== dependencies: - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.3" "@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": - version "4.11.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" - integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== + version "4.11.2" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.2.tgz#dc6925ab4ea52d3b9d6da204a3f0dd9c3852e3ad" + integrity sha512-2WwyTYNVaMNUWPZTOJdkax9iqTdirrApgTbk+Qoq5EPX6myqZvG8QGFRgdKmkjKVG6/G/a565vpPauHk0+hpBA== "@eslint/eslintrc@^2.1.4": version "2.1.4" @@ -324,42 +324,42 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== "@floating-ui/core@^1.6.0": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.7.tgz#7602367795a390ff0662efd1c7ae8ca74e75fb12" - integrity sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g== + version "1.6.8" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.8.tgz#aa43561be075815879305965020f492cdb43da12" + integrity sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA== dependencies: - "@floating-ui/utils" "^0.2.7" + "@floating-ui/utils" "^0.2.8" "@floating-ui/dom@^1.4.3": - version "1.6.10" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.10.tgz#b74c32f34a50336c86dcf1f1c845cf3a39e26d6f" - integrity sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A== + version "1.6.11" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.11.tgz#8631857838d34ee5712339eb7cbdfb8ad34da723" + integrity sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ== dependencies: "@floating-ui/core" "^1.6.0" - "@floating-ui/utils" "^0.2.7" + "@floating-ui/utils" "^0.2.8" -"@floating-ui/utils@^0.2.7": - version "0.2.7" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.7.tgz#d0ece53ce99ab5a8e37ebdfe5e32452a2bfc073e" - integrity sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA== +"@floating-ui/utils@^0.2.8": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62" + integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== "@fluent/bundle@^0.18.0": version "0.18.0" resolved "https://registry.yarnpkg.com/@fluent/bundle/-/bundle-0.18.0.tgz#bf67e306719a33baf3b66c88af5ac427d7800dbd" integrity sha512-8Wfwu9q8F9g2FNnv82g6Ch/E1AW1wwljsUOolH5NEtdJdv0sZTuWvfCM7c3teB9dzNaJA8rn4khpidpozHWYEA== -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== dependencies: - "@humanwhocodes/object-schema" "^2.0.2" + "@humanwhocodes/object-schema" "^2.0.3" debug "^4.3.1" minimatch "^3.0.5" @@ -368,7 +368,7 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.2": +"@humanwhocodes/object-schema@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== @@ -430,9 +430,9 @@ integrity sha512-WQ2gDll12T9WD34fdRFgQVgO8bag3gavrAgJ0frN4phlwdJARpE6gO1YvLEMJR0KKgoc+/Ea/A0Pp11I00xBvw== "@mdn/browser-compat-data@^5.2.34", "@mdn/browser-compat-data@^5.3.13": - version "5.5.50" - resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-5.5.50.tgz#4a51fa4d64dc8e921649e99e676a5b0973dce45b" - integrity sha512-7Vlybx9Vao3kQNJGps2sFnBSq5uWcUsZtlwU2bUzeeKbwzKO507V7K+vv0TlfQ1qunDy1PiRz6BGtdxyMMD5tQ== + version "5.6.10" + resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-5.6.10.tgz#5602542b6cb151b8489e5dcd73faa046a0603770" + integrity sha512-plMgRN6pGGaHxvH5Y5DJcWR3C8tC/HHN18saHAWu395XfNRtFMrKPiDeRGQWIHjTXFbQVLra2nFG5GKyezXy+Q== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -462,20 +462,103 @@ dependencies: semver "^7.3.5" +"@parcel/watcher-android-arm64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84" + integrity sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg== + +"@parcel/watcher-darwin-arm64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz#c817c7a3b4f3a79c1535bfe54a1c2818d9ffdc34" + integrity sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA== + +"@parcel/watcher-darwin-x64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz#1a3f69d9323eae4f1c61a5f480a59c478d2cb020" + integrity sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg== + +"@parcel/watcher-freebsd-x64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz#0d67fef1609f90ba6a8a662bc76a55fc93706fc8" + integrity sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w== + +"@parcel/watcher-linux-arm-glibc@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz#ce5b340da5829b8e546bd00f752ae5292e1c702d" + integrity sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA== + +"@parcel/watcher-linux-arm64-glibc@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz#6d7c00dde6d40608f9554e73998db11b2b1ff7c7" + integrity sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA== + +"@parcel/watcher-linux-arm64-musl@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz#bd39bc71015f08a4a31a47cd89c236b9d6a7f635" + integrity sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA== + +"@parcel/watcher-linux-x64-glibc@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz#0ce29966b082fb6cdd3de44f2f74057eef2c9e39" + integrity sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg== + +"@parcel/watcher-linux-x64-musl@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz#d2ebbf60e407170bb647cd6e447f4f2bab19ad16" + integrity sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ== + +"@parcel/watcher-win32-arm64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz#eb4deef37e80f0b5e2f215dd6d7a6d40a85f8adc" + integrity sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg== + +"@parcel/watcher-win32-ia32@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz#94fbd4b497be39fd5c8c71ba05436927842c9df7" + integrity sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw== + +"@parcel/watcher-win32-x64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz#4bf920912f67cae5f2d264f58df81abfea68dadf" + integrity sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A== + +"@parcel/watcher@^2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.4.1.tgz#a50275151a1bb110879c6123589dba90c19f1bf8" + integrity sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA== + dependencies: + detect-libc "^1.0.3" + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^7.0.0" + optionalDependencies: + "@parcel/watcher-android-arm64" "2.4.1" + "@parcel/watcher-darwin-arm64" "2.4.1" + "@parcel/watcher-darwin-x64" "2.4.1" + "@parcel/watcher-freebsd-x64" "2.4.1" + "@parcel/watcher-linux-arm-glibc" "2.4.1" + "@parcel/watcher-linux-arm64-glibc" "2.4.1" + "@parcel/watcher-linux-arm64-musl" "2.4.1" + "@parcel/watcher-linux-x64-glibc" "2.4.1" + "@parcel/watcher-linux-x64-musl" "2.4.1" + "@parcel/watcher-win32-arm64" "2.4.1" + "@parcel/watcher-win32-ia32" "2.4.1" + "@parcel/watcher-win32-x64" "2.4.1" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@polka/url@^1.0.0-next.24": - version "1.0.0-next.25" - resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.25.tgz#f077fdc0b5d0078d30893396ff4827a13f99e817" - integrity sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ== + version "1.0.0-next.28" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73" + integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw== "@poppanator/sveltekit-svg@^5.0.0-svelte5.5": - version "5.0.0-svelte5.5" - resolved "https://registry.yarnpkg.com/@poppanator/sveltekit-svg/-/sveltekit-svg-5.0.0-svelte5.5.tgz#0d9fc6d010a645cb4dde18cdf972baab481677b9" - integrity sha512-4OmrM0Q9keA/QyEqwfnq2d69mq/M+9cMCvdPXQ5nIzEIx4D2d/6DthJC9aaX+fNCygZkaJ77yaarVVrZRQ8cEA== + version "5.0.0" + resolved "https://registry.yarnpkg.com/@poppanator/sveltekit-svg/-/sveltekit-svg-5.0.0.tgz#9bb43de812871261de18926b4a1b36c32a91ed04" + integrity sha512-b7hk55SF0HjTS+xFgMG20hy6W0F/m+yRA/ZWcjnsa391rB3Ys3desCiUyIKQYcfvcyuRiQCPedUJMYgu00VdCA== dependencies: "@rollup/pluginutils" "^5.1.0" @@ -485,93 +568,93 @@ integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== "@rollup/pluginutils@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" - integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== + version "5.1.3" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.3.tgz#3001bf1a03f3ad24457591f2c259c8e514e0dbdf" + integrity sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A== dependencies: "@types/estree" "^1.0.0" estree-walker "^2.0.2" - picomatch "^2.3.1" + picomatch "^4.0.2" -"@rollup/rollup-android-arm-eabi@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5" - integrity sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w== +"@rollup/rollup-android-arm-eabi@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54" + integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA== -"@rollup/rollup-android-arm64@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz#654ca1049189132ff602bfcf8df14c18da1f15fb" - integrity sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA== +"@rollup/rollup-android-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e" + integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA== -"@rollup/rollup-darwin-arm64@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz#6d241d099d1518ef0c2205d96b3fa52e0fe1954b" - integrity sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q== +"@rollup/rollup-darwin-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f" + integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA== -"@rollup/rollup-darwin-x64@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz#42bd19d292a57ee11734c980c4650de26b457791" - integrity sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw== +"@rollup/rollup-darwin-x64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724" + integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ== -"@rollup/rollup-linux-arm-gnueabihf@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz#f23555ee3d8fe941c5c5fd458cd22b65eb1c2232" - integrity sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ== +"@rollup/rollup-linux-arm-gnueabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb" + integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA== -"@rollup/rollup-linux-arm-musleabihf@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz#f3bbd1ae2420f5539d40ac1fde2b38da67779baa" - integrity sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg== +"@rollup/rollup-linux-arm-musleabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3" + integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw== -"@rollup/rollup-linux-arm64-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz#7abe900120113e08a1f90afb84c7c28774054d15" - integrity sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw== +"@rollup/rollup-linux-arm64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496" + integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA== -"@rollup/rollup-linux-arm64-musl@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz#9e655285c8175cd44f57d6a1e8e5dedfbba1d820" - integrity sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA== +"@rollup/rollup-linux-arm64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065" + integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw== -"@rollup/rollup-linux-powerpc64le-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz#9a79ae6c9e9d8fe83d49e2712ecf4302db5bef5e" - integrity sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg== +"@rollup/rollup-linux-powerpc64le-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d" + integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw== -"@rollup/rollup-linux-riscv64-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz#67ac70eca4ace8e2942fabca95164e8874ab8128" - integrity sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA== +"@rollup/rollup-linux-riscv64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983" + integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg== -"@rollup/rollup-linux-s390x-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz#9f883a7440f51a22ed7f99e1d070bd84ea5005fc" - integrity sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q== +"@rollup/rollup-linux-s390x-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58" + integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g== -"@rollup/rollup-linux-x64-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz#70116ae6c577fe367f58559e2cffb5641a1dd9d0" - integrity sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg== +"@rollup/rollup-linux-x64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b" + integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A== -"@rollup/rollup-linux-x64-musl@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz#f473f88219feb07b0b98b53a7923be716d1d182f" - integrity sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g== +"@rollup/rollup-linux-x64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127" + integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ== -"@rollup/rollup-win32-arm64-msvc@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz#4349482d17f5d1c58604d1c8900540d676f420e0" - integrity sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw== +"@rollup/rollup-win32-arm64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5" + integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ== -"@rollup/rollup-win32-ia32-msvc@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz#a6fc39a15db618040ec3c2a24c1e26cb5f4d7422" - integrity sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g== +"@rollup/rollup-win32-ia32-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2" + integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ== -"@rollup/rollup-win32-x64-msvc@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz#3dd5d53e900df2a40841882c02e56f866c04d202" - integrity sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q== +"@rollup/rollup-win32-x64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz#0574d7e87b44ee8511d08cc7f914bcb802b70818" + integrity sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw== "@rtsao/scc@^1.1.0": version "1.1.0" @@ -589,18 +672,18 @@ integrity sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw== "@sveltejs/adapter-static@^3.0.0": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@sveltejs/adapter-static/-/adapter-static-3.0.4.tgz#5ab50410156c1c71dc78404e498fc38207aa59e4" - integrity sha512-Qm4GAHCnRXwfWG9/AtnQ7mqjyjTs7i0Opyb8H2KH9rMR7fLxqiPx/tXeoE6HHo66+72CjyOb4nFH3lrejY4vzA== + version "3.0.6" + resolved "https://registry.yarnpkg.com/@sveltejs/adapter-static/-/adapter-static-3.0.6.tgz#a580ad86aa90a52b19b6440f3c9521bd731211c1" + integrity sha512-MGJcesnJWj7FxDcB/GbrdYD3q24Uk0PIL4QIX149ku+hlJuj//nxUbb0HxUTpjkecWfHjVveSUnUaQWnPRXlpg== "@sveltejs/kit@^2.4.1": - version "2.5.25" - resolved "https://registry.yarnpkg.com/@sveltejs/kit/-/kit-2.5.25.tgz#618bc81b0f0c9afad73d2d8e5352b7462b949de3" - integrity sha512-5hBSEN8XEjDZ5+2bHkFh8Z0QyOk0C187cyb12aANe1c8aeKbfu5ZD5XaC2vEH4h0alJFDXPdUkXQBmeeXeMr1A== + version "2.7.3" + resolved "https://registry.yarnpkg.com/@sveltejs/kit/-/kit-2.7.3.tgz#83a4d7145d89a16e939c6c72f1fe928a176c7986" + integrity sha512-Vx7nq5MJ86I8qXYsVidC5PX6xm+uxt8DydvOdmJoyOK7LvGP18OFEG359yY+aa51t6pENvqZAMqAREQQx1OI2Q== dependencies: "@types/cookie" "^0.6.0" cookie "^0.6.0" - devalue "^5.0.0" + devalue "^5.1.0" esm-env "^1.0.0" import-meta-resolve "^4.1.0" kleur "^4.1.5" @@ -608,27 +691,27 @@ mrmime "^2.0.0" sade "^1.8.1" set-cookie-parser "^2.6.0" - sirv "^2.0.4" + sirv "^3.0.0" tiny-glob "^0.2.9" "@sveltejs/vite-plugin-svelte-inspector@^3.0.0-next.0||^3.0.0": - version "3.0.0-next.3" - resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-3.0.0-next.3.tgz#1891b5e22e49c0e8dfbde83d573d0eeb8365697f" - integrity sha512-kuGJ2CZ5lAw3gKF8Kw0AfKtUJWbwdlDHY14K413B0MCyrzvQvsKTorwmwZcky0+QqY6RnVIZ/5FttB9bQmkLXg== + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-3.0.1.tgz#006bcab6ea90e09c65459133d4e3eaa6b1e83e28" + integrity sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ== dependencies: - debug "^4.3.5" + debug "^4.3.7" -"@sveltejs/vite-plugin-svelte@4.0.0-next.7": - version "4.0.0-next.7" - resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.0-next.7.tgz#2139be5083d2b1d117740c69e4e700156b1abeb2" - integrity sha512-yMUnAqquoayvBDztk1rWUgdtvjv7YcHgopCAB7sWl9SQht8U/7lqwTlJU0ZTAY09pFFRe6bbakd7YoiyyIvJiA== +"@sveltejs/vite-plugin-svelte@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.0.tgz#4e7c2fe6fd262f6bbd7dc82085a76654cbaeafe5" + integrity sha512-kpVJwF+gNiMEsoHaw+FJL76IYiwBikkxYU83+BpqQLdVMff19KeRKLd2wisS8niNBMJ2omv5gG+iGDDwd8jzag== dependencies: "@sveltejs/vite-plugin-svelte-inspector" "^3.0.0-next.0||^3.0.0" - debug "^4.3.6" + debug "^4.3.7" deepmerge "^4.3.1" kleur "^4.1.5" - magic-string "^0.30.11" - vitefu "^1.0.2" + magic-string "^0.30.12" + vitefu "^1.0.3" "@tootallnate/once@2": version "2.0.0" @@ -792,9 +875,9 @@ "@types/d3-time" "*" "@types/d3-selection@*": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.10.tgz#98cdcf986d0986de6912b5892e7c015a95ca27fe" - integrity sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg== + version "3.0.11" + resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.11.tgz#bd7a45fc0a8c3167a631675e61bc2ca2b058d4a3" + integrity sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w== "@types/d3-shape@*": version "3.1.6" @@ -819,9 +902,9 @@ integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw== "@types/d3-transition@*": - version "3.0.8" - resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.8.tgz#677707f5eed5b24c66a1918cde05963021351a8f" - integrity sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ== + version "3.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.9.tgz#1136bc57e9ddb3c390dccc9b5ff3b7d2b8d94706" + integrity sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg== dependencies: "@types/d3-selection" "*" @@ -870,14 +953,14 @@ "@types/d3-zoom" "*" "@types/diff@^5.0.0": - version "5.2.2" - resolved "https://registry.yarnpkg.com/@types/diff/-/diff-5.2.2.tgz#d430dbb1da6739f1e2565c2c80b54184d4c77658" - integrity sha512-qVqLpd49rmJA2nZzLVsmfS/aiiBpfVE95dHhPVwG0NmSBAt+riPxnj53wq2oBq5m4Q2RF1IWFEUpnZTgrQZfEQ== + version "5.2.3" + resolved "https://registry.yarnpkg.com/@types/diff/-/diff-5.2.3.tgz#dcdcfa40df9f011f9465180e0196dfbd921971d9" + integrity sha512-K0Oqlrq3kQMaO2RhfrNQX5trmt+XLyom88zS0u84nnIcLvFnRUMRRHmrGny5GSM+kNO9IZLARsdQHDzkhAgmrQ== -"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0", "@types/estree@^1.0.1", "@types/estree@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.1", "@types/estree@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== "@types/fabric@^5.3.7": version "5.3.9" @@ -890,9 +973,9 @@ integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg== "@types/jquery@*", "@types/jquery@^3.5.0": - version "3.5.30" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.30.tgz#888d584cbf844d3df56834b69925085038fd80f7" - integrity sha512-nbWKkkyb919DOUxjmRVk8vwtDb0/k8FKncmUKFi+NY+QXqWltooxTrswvz4LspQwxvLdvzBN1TImr6cw3aQx2A== + version "3.5.32" + resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.32.tgz#3eb0da20611b92c7c49ebed6163b52a4fdc57def" + integrity sha512-b9Xbf4CkMqS02YH8zACqN1xzdxc3cO735Qe5AbSUFmyOiaWAbcpqh9Wna+Uk0vgACvoQHpWDg2rGdHkYPLmCiQ== dependencies: "@types/sizzle" "*" @@ -921,9 +1004,9 @@ "@types/lodash" "*" "@types/lodash@*": - version "4.17.7" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.7.tgz#2f776bcb53adc9e13b2c0dfd493dfcbd7de43612" - integrity sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA== + version "4.17.12" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.12.tgz#25d71312bf66512105d71e55d42e22c36bcfc689" + integrity sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ== "@types/marked@^5.0.0": version "5.0.2" @@ -931,9 +1014,9 @@ integrity sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg== "@types/node@^16.10.2": - version "16.18.107" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.107.tgz#9185eaebaf7d002a67976d61ae8a9a808fc84829" - integrity sha512-VSha8UIBpCpETub8FZ1nXkODXm+k+YRwpuVQsF3zOuD6QyPQeuIdPRm6IBVa2E5en58CUFJfaw6GmYHP2q/vkQ== + version "16.18.115" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.115.tgz#0bb385c4b1a1a996d6bf9d79e5ae786ce03cae51" + integrity sha512-NF5ajYn+dq0tRfswdyp8Df75h7D9z+L8TCIwrXoh46ZLK6KZVXkRhf/luXaZytvm/keUo9vU4m1Bg39St91a5w== "@types/pug@^2.0.6": version "2.0.10" @@ -946,9 +1029,9 @@ integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== "@types/sizzle@*": - version "2.3.8" - resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.8.tgz#518609aefb797da19bf222feb199e8f653ff7627" - integrity sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg== + version "2.3.9" + resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.9.tgz#d4597dbd4618264c414d7429363e3f50acb66ea2" + integrity sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w== "@types/tern@*": version "0.23.9" @@ -1131,9 +1214,9 @@ acorn-walk@^7.1.1: integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== acorn-walk@^8.3.2: - version "8.3.3" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" - integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== dependencies: acorn "^8.11.0" @@ -1142,10 +1225,10 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.11.0, acorn@^8.11.3, acorn@^8.5.0, acorn@^8.9.0: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== +acorn@^8.11.0, acorn@^8.12.1, acorn@^8.5.0, acorn@^8.9.0: + version "8.13.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" + integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== agent-base@6: version "6.0.2" @@ -1170,9 +1253,9 @@ ansi-regex@^5.0.1: integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" @@ -1204,7 +1287,7 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -aria-query@^5.3.0: +aria-query@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== @@ -1309,7 +1392,7 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" -axobject-query@^4.0.0: +axobject-query@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== @@ -1367,14 +1450,14 @@ browser-process-hrtime@^1.0.0: integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== browserslist@^4.21.10: - version "4.23.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" - integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== + version "4.24.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" + integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== dependencies: - caniuse-lite "^1.0.30001646" - electron-to-chromium "^1.5.4" + caniuse-lite "^1.0.30001669" + electron-to-chromium "^1.5.41" node-releases "^2.0.18" - update-browserslist-db "^1.1.0" + update-browserslist-db "^1.1.1" buffer-crc32@^1.0.0: version "1.0.0" @@ -1407,10 +1490,10 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -caniuse-lite@^1.0.30001431, caniuse-lite@^1.0.30001524, caniuse-lite@^1.0.30001646: - version "1.0.30001655" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz#0ce881f5a19a2dcfda2ecd927df4d5c1684b982f" - integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg== +caniuse-lite@^1.0.30001431, caniuse-lite@^1.0.30001524, caniuse-lite@^1.0.30001669: + version "1.0.30001671" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001671.tgz#c660a8a0bf6bb8eedaac683d29074e455e84e3f1" + integrity sha512-jocyVaSSfXg2faluE6hrWkMgDOiULBMca4QLtDT39hw1YxaIPHWc1CcTCKkPmHgGH6tKji6ZNbMSmUAvENf2/A== canvas@^2.8.0, "canvas@npm:empty-npm-package": version "1.0.0" @@ -1461,16 +1544,16 @@ check-error@^1.0.3: fsevents "~2.3.2" chokidar@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.0.tgz#4d603963e5dd762dc5c7bb1cb5664e53a3002225" - integrity sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA== + version "4.0.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.1.tgz#4a6dff66798fb0f72a94f616abbd7e1a19f31d41" + integrity sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA== dependencies: readdirp "^4.0.1" codemirror@^5.63.1: - version "5.65.17" - resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.17.tgz#00d71f34c3518471ae4c0de23a2f8bb39a6df6ca" - integrity sha512-1zOsUx3lzAOu/gnMAZkQ9kpIHcPYOc9y1Fbm2UVk5UBPkdq380nhkelG0qUwm1f7wPvTbndu9ZYlug35EwAZRQ== + version "5.65.18" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.18.tgz#d7146e4271135a9b4adcd023a270185457c9c428" + integrity sha512-Gaz4gHnkbHMGgahNt3CA5HBk5lLQBqmD/pBgeB4kQU6OedZmqMBjlRF0LSrp2tJ4wlLNPm2FfaUd1pDy0mdlpA== color-convert@^2.0.1: version "2.0.1" @@ -1501,10 +1584,10 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -confbox@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579" - integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== cookie@^0.6.0: version "0.6.0" @@ -1868,12 +1951,12 @@ data-view-byte-offset@^1.0.0: es-errors "^1.3.0" is-data-view "^1.0.1" -debug@4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" - integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== +debug@4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" + ms "^2.1.3" debug@^3.2.7: version "3.2.7" @@ -1882,13 +1965,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.3.5, debug@^4.3.6: - version "4.3.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== - dependencies: - ms "^2.1.3" - decimal.js@^10.3.1: version "10.4.3" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" @@ -1946,10 +2022,15 @@ detect-indent@^6.1.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== -devalue@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/devalue/-/devalue-5.0.0.tgz#1ca0099a7d715b4d6cac3924e770ccbbc584ad98" - integrity sha512-gO+/OMXF7488D+u3ue+G7Y4AA3ZmUnB3eHJXmBTgNHvr4ZNzl36A0ZtG+XCRNYCkYx/bFmw4qtkoFLa+wSrwAA== +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + +devalue@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/devalue/-/devalue-5.1.1.tgz#a71887ac0f354652851752654e4bd435a53891ae" + integrity sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw== diff-sequences@^29.6.3: version "29.6.3" @@ -2020,28 +2101,28 @@ domutils@^3.0.1: domhandler "^5.0.3" dprint@^0.47.2: - version "0.47.2" - resolved "https://registry.yarnpkg.com/dprint/-/dprint-0.47.2.tgz#f3aca518324b9948066652c87e4c4a3bc509869d" - integrity sha512-geUcVIIrmLaY+YtuOl4gD7J/QCjsXZa5gUqre9sO6cgH0X/Fa9heBN3l/AWVII6rKPw45ATuCSDWz1pyO+HkPQ== + version "0.47.4" + resolved "https://registry.yarnpkg.com/dprint/-/dprint-0.47.4.tgz#6b944110d5dc942ae5787f6d76931624cb4756cc" + integrity sha512-eyjiV7+aW34tTSTwXe0v6aQtl9zM3UrjAMc3VggcvvvwWBlzHXA4651w1odnY58wja3kxiwnP6ok0kzfOZHmrg== optionalDependencies: - "@dprint/darwin-arm64" "0.47.2" - "@dprint/darwin-x64" "0.47.2" - "@dprint/linux-arm64-glibc" "0.47.2" - "@dprint/linux-arm64-musl" "0.47.2" - "@dprint/linux-x64-glibc" "0.47.2" - "@dprint/linux-x64-musl" "0.47.2" - "@dprint/win32-arm64" "0.47.2" - "@dprint/win32-x64" "0.47.2" + "@dprint/darwin-arm64" "0.47.4" + "@dprint/darwin-x64" "0.47.4" + "@dprint/linux-arm64-glibc" "0.47.4" + "@dprint/linux-arm64-musl" "0.47.4" + "@dprint/linux-x64-glibc" "0.47.4" + "@dprint/linux-x64-musl" "0.47.4" + "@dprint/win32-arm64" "0.47.4" + "@dprint/win32-x64" "0.47.4" eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -electron-to-chromium@^1.5.4: - version "1.5.13" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6" - integrity sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q== +electron-to-chromium@^1.5.41: + version "1.5.47" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.47.tgz#ef0751bc19b28be8ee44cd8405309de3bf3b20c7" + integrity sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ== emoji-regex@^8.0.0: version "8.0.0" @@ -2168,9 +2249,9 @@ esbuild-sass-plugin@^2: sass "^1.7.3" esbuild-svelte@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/esbuild-svelte/-/esbuild-svelte-0.8.1.tgz#12d716f420e0b9516ba3cf9f7c264432afac8a1a" - integrity sha512-iswZSetqRxYaQoWMd38Gu6AanIL6KFsVj8/unei7qTaxjAkRDulW62/Bc5nmeogKBWekBvrPOE106wui7gYARQ== + version "0.8.2" + resolved "https://registry.yarnpkg.com/esbuild-svelte/-/esbuild-svelte-0.8.2.tgz#f6c09b57879caabd068685684b47f42dbd266396" + integrity sha512-tG97WrhH/OH8wFCmRBk6sRggMVMPNZDktGx1jJcvh9Obvjwm8M1UYoXmliuLL+4fs/wfyVVwM2fvyNYz2e6UPQ== dependencies: "@jridgewell/trace-mapping" "^0.3.19" @@ -2231,7 +2312,7 @@ esbuild@^0.21.3: "@esbuild/win32-ia32" "0.21.5" "@esbuild/win32-x64" "0.21.5" -escalade@^3.1.2: +escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== @@ -2268,10 +2349,10 @@ eslint-import-resolver-node@^0.3.9: is-core-module "^2.13.0" resolve "^1.22.4" -eslint-module-utils@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.9.0.tgz#95d4ac038a68cd3f63482659dffe0883900eb342" - integrity sha512-McVbYmwA3NEKwRQY5g4aWMdcZE5xZxV8i8l7CqJSrameuGSQJtSWaL/LxTEzSKKaCcOhlpDR8XEfYXWPrdo/ZQ== +eslint-module-utils@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== dependencies: debug "^3.2.7" @@ -2289,9 +2370,9 @@ eslint-plugin-compat@^4.1.4: semver "^7.5.4" eslint-plugin-import@^2.25.4: - version "2.30.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz#21ceea0fc462657195989dd780e50c92fe95f449" - integrity sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw== + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== dependencies: "@rtsao/scc" "^1.1.0" array-includes "^3.1.8" @@ -2301,7 +2382,7 @@ eslint-plugin-import@^2.25.4: debug "^3.2.7" doctrine "^2.1.0" eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.9.0" + eslint-module-utils "^2.12.0" hasown "^2.0.2" is-core-module "^2.15.1" is-glob "^4.0.3" @@ -2310,24 +2391,25 @@ eslint-plugin-import@^2.25.4: object.groupby "^1.0.3" object.values "^1.2.0" semver "^6.3.1" + string.prototype.trimend "^1.0.8" tsconfig-paths "^3.15.0" eslint-plugin-svelte@^2: - version "2.43.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-svelte/-/eslint-plugin-svelte-2.43.0.tgz#bcfaec0e114e3450071415c3ef9c57dcf7ce118f" - integrity sha512-REkxQWvg2pp7QVLxQNa+dJ97xUqRe7Y2JJbSWkHSuszu0VcblZtXkPBPckkivk99y5CdLw4slqfPylL2d/X4jQ== + version "2.46.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.0.tgz#87bcc2820233065f79114012203b082319ff03e9" + integrity sha512-1A7iEMkzmCZ9/Iz+EAfOGYL8IoIG6zeKEq1SmpxGeM5SXmoQq+ZNnCpXFVJpsxPWYx8jIVGMerQMzX20cqUl0g== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@jridgewell/sourcemap-codec" "^1.4.15" eslint-compat-utils "^0.5.1" esutils "^2.0.3" - known-css-properties "^0.34.0" + known-css-properties "^0.35.0" postcss "^8.4.38" postcss-load-config "^3.1.4" postcss-safe-parser "^6.0.0" postcss-selector-parser "^6.1.0" semver "^7.6.2" - svelte-eslint-parser "^0.41.0" + svelte-eslint-parser "^0.43.0" eslint-scope@^5.1.1: version "5.1.1" @@ -2351,15 +2433,15 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.44.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" "@ungap/structured-clone" "^1.2.0" @@ -2570,9 +2652,9 @@ foreground-child@^3.1.0: signal-exit "^4.0.1" form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -2639,9 +2721,9 @@ get-symbol-description@^1.0.2: get-intrinsic "^1.2.4" get-tsconfig@^4.7.2: - version "4.8.0" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.0.tgz#125dc13a316f61650a12b20c97c11b8fd996fedd" - integrity sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw== + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== dependencies: resolve-pkg-maps "^1.0.0" @@ -3156,10 +3238,10 @@ kleur@^4.1.5: resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== -known-css-properties@^0.34.0: - version "0.34.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.34.0.tgz#ccd7e9f4388302231b3f174a8b1d5b1f7b576cea" - integrity sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ== +known-css-properties@^0.35.0: + version "0.35.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.35.0.tgz#f6f8e40ab4e5700fa32f5b2ef5218a56bc853bd6" + integrity sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A== levn@^0.4.1: version "0.4.1" @@ -3248,10 +3330,10 @@ lru-cache@^7.5.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -magic-string@^0.30.11, magic-string@^0.30.5: - version "0.30.11" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.11.tgz#301a6f93b3e8c2cb13ac1a7a673492c0dfd12954" - integrity sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A== +magic-string@^0.30.11, magic-string@^0.30.12, magic-string@^0.30.5: + version "0.30.12" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.12.tgz#9eb11c9d072b9bcb4940a5b2c2e1a217e4ee1a60" + integrity sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw== dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" @@ -3285,7 +3367,7 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.4: +micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -3351,15 +3433,15 @@ mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mlly@^1.4.2, mlly@^1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.1.tgz#e0336429bb0731b6a8e887b438cbdae522c8f32f" - integrity sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA== +mlly@^1.4.2, mlly@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.2.tgz#21c0d04543207495b8d867eff0ac29fac9a023c0" + integrity sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA== dependencies: - acorn "^8.11.3" + acorn "^8.12.1" pathe "^1.1.2" - pkg-types "^1.1.1" - ufo "^1.5.3" + pkg-types "^1.2.0" + ufo "^1.5.4" mri@^1.1.0: version "1.2.0" @@ -3371,11 +3453,6 @@ mrmime@^2.0.0: resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -3396,6 +3473,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +node-addon-api@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + node-releases@^2.0.18: version "2.0.18" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" @@ -3443,9 +3525,9 @@ nth-check@^2.0.1: boolbase "^1.0.0" nwsapi@^2.2.0: - version "2.2.12" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" - integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== + version "2.2.13" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.13.tgz#e56b4e98960e7a040e5474536587e599c4ff4655" + integrity sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ== object-inspect@^1.13.1: version "1.13.2" @@ -3543,9 +3625,9 @@ p-locate@^5.0.0: p-limit "^3.0.2" package-json-from-dist@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" - integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== parent-module@^1.0.0: version "1.0.1" @@ -3607,23 +3689,28 @@ pathval@^1.1.1: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" - integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pkg-types@^1.0.3, pkg-types@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.2.0.tgz#d0268e894e93acff11a6279de147e83354ebd42d" - integrity sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA== +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +pkg-types@^1.0.3, pkg-types@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.2.1.tgz#6ac4e455a5bb4b9a6185c1c79abd544c901db2e5" + integrity sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw== dependencies: - confbox "^0.1.7" - mlly "^1.7.1" + confbox "^0.1.8" + mlly "^1.7.2" pathe "^1.1.2" possible-typed-array-names@^1.0.0: @@ -3657,16 +3744,7 @@ postcss-selector-parser@^6.1.0: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss@^8.4.38, postcss@^8.4.39: - version "8.4.44" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.44.tgz#d56834ef6508610ba224bb22b2457b2169ed0480" - integrity sha512-Aweb9unOEpQ3ezu4Q00DPvvM2ZTUitJdNKeP/+uQgr1IBIqu574IaZoURId7BKtWMREwzKa9OgzPzezWGPWFQw== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.1" - source-map-js "^1.2.0" - -postcss@^8.4.43: +postcss@^8.4.38, postcss@^8.4.39, postcss@^8.4.43: version "8.4.47" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== @@ -3681,9 +3759,9 @@ prelude-ls@^1.2.1: integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prettier-plugin-svelte@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.6.tgz#22e5b6783a2c87bfe112e0f4b1886ea3db236bf4" - integrity sha512-Y1XWLw7vXUQQZmgv1JAEiLcErqUniAF2wO7QJsw8BVMvpLET2dI5WpEIEJx1r11iHVdSMzQxivyfrH9On9t2IQ== + version "3.2.7" + resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.7.tgz#10db2d553b48c6ed412e2d00688f8d2eaa274f8a" + integrity sha512-/Dswx/ea0lV34If1eDcG3nulQ63YNr5KPDfMsjbdtpSWOxKKJ7nAc2qlVuYwEvCr4raIuredNoR7K4JCkmTGaQ== prettier@^2.4.1: version "2.8.8" @@ -3748,9 +3826,9 @@ read-package-json@^6.0.0: npm-normalize-package-bin "^3.0.0" readdirp@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.1.tgz#b2fe35f8dca63183cd3b86883ecc8f720ea96ae6" - integrity sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw== + version "4.0.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a" + integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA== readdirp@~3.6.0: version "3.6.0" @@ -3760,14 +3838,14 @@ readdirp@~3.6.0: picomatch "^2.2.1" regexp.prototype.flags@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== + version "1.5.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42" + integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ== dependencies: - call-bind "^1.0.6" + call-bind "^1.0.7" define-properties "^1.2.1" es-errors "^1.3.0" - set-function-name "^2.0.1" + set-function-name "^2.0.2" requires-port@^1.0.0: version "1.0.0" @@ -3818,28 +3896,28 @@ robust-predicates@^3.0.2: integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== rollup@^4.20.0: - version "4.22.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.22.4.tgz#4135a6446671cd2a2453e1ad42a45d5973ec3a0f" - integrity sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A== + version "4.24.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.0.tgz#c14a3576f20622ea6a5c9cad7caca5e6e9555d05" + integrity sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg== dependencies: - "@types/estree" "1.0.5" + "@types/estree" "1.0.6" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.22.4" - "@rollup/rollup-android-arm64" "4.22.4" - "@rollup/rollup-darwin-arm64" "4.22.4" - "@rollup/rollup-darwin-x64" "4.22.4" - "@rollup/rollup-linux-arm-gnueabihf" "4.22.4" - "@rollup/rollup-linux-arm-musleabihf" "4.22.4" - "@rollup/rollup-linux-arm64-gnu" "4.22.4" - "@rollup/rollup-linux-arm64-musl" "4.22.4" - "@rollup/rollup-linux-powerpc64le-gnu" "4.22.4" - "@rollup/rollup-linux-riscv64-gnu" "4.22.4" - "@rollup/rollup-linux-s390x-gnu" "4.22.4" - "@rollup/rollup-linux-x64-gnu" "4.22.4" - "@rollup/rollup-linux-x64-musl" "4.22.4" - "@rollup/rollup-win32-arm64-msvc" "4.22.4" - "@rollup/rollup-win32-ia32-msvc" "4.22.4" - "@rollup/rollup-win32-x64-msvc" "4.22.4" + "@rollup/rollup-android-arm-eabi" "4.24.0" + "@rollup/rollup-android-arm64" "4.24.0" + "@rollup/rollup-darwin-arm64" "4.24.0" + "@rollup/rollup-darwin-x64" "4.24.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.24.0" + "@rollup/rollup-linux-arm-musleabihf" "4.24.0" + "@rollup/rollup-linux-arm64-gnu" "4.24.0" + "@rollup/rollup-linux-arm64-musl" "4.24.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.24.0" + "@rollup/rollup-linux-riscv64-gnu" "4.24.0" + "@rollup/rollup-linux-s390x-gnu" "4.24.0" + "@rollup/rollup-linux-x64-gnu" "4.24.0" + "@rollup/rollup-linux-x64-musl" "4.24.0" + "@rollup/rollup-win32-arm64-msvc" "4.24.0" + "@rollup/rollup-win32-ia32-msvc" "4.24.0" + "@rollup/rollup-win32-x64-msvc" "4.24.0" fsevents "~2.3.2" run-parallel@^1.1.9: @@ -3905,10 +3983,11 @@ sass@<1.77: source-map-js ">=0.6.2 <2.0.0" sass@^1.7.3: - version "1.79.3" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.79.3.tgz#7811b000eb68195fe51dea89177e73e7ef7f546f" - integrity sha512-m7dZxh0W9EZ3cw50Me5GOuYm/tVAJAn91SUnohLRo9cXBixGUOdvmryN+dXpwR831bhoY3Zv7rEFt85PUwTmzA== + version "1.80.4" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.80.4.tgz#bc0418fd796cad2f1a1309d8b4d7fe44b7027de0" + integrity sha512-rhMQ2tSF5CsuuspvC94nPM9rToiAFw2h3JTrLlgmNw1MH79v8Cr3DH6KF6o6r+8oofY3iYVPUf66KzC8yuVN1w== dependencies: + "@parcel/watcher" "^2.4.1" chokidar "^4.0.0" immutable "^4.0.0" source-map-js ">=0.6.2 <2.0.0" @@ -3931,9 +4010,9 @@ semver@^6.3.1: integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== set-cookie-parser@^2.6.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz#ef5552b56dc01baae102acb5fc9fb8cd060c30f9" - integrity sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ== + version "2.7.1" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943" + integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ== set-function-length@^1.2.1: version "1.2.2" @@ -3947,7 +4026,7 @@ set-function-length@^1.2.1: gopd "^1.0.1" has-property-descriptors "^1.0.2" -set-function-name@^2.0.1: +set-function-name@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== @@ -3989,10 +4068,10 @@ signal-exit@^4.0.1, signal-exit@^4.1.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== -sirv@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0" - integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ== +sirv@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-3.0.0.tgz#f8d90fc528f65dff04cb597a88609d4e8a4361ce" + integrity sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg== dependencies: "@polka/url" "^1.0.0-next.24" mrmime "^2.0.0" @@ -4018,12 +4097,7 @@ sorcery@^0.11.0: minimist "^1.2.0" sander "^0.5.0" -"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== - -source-map-js@^1.2.1: +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -4101,7 +4175,6 @@ std-env@^3.5.0: integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: - name string-width-cjs version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4214,10 +4287,10 @@ svelte-check@^3.4.4: svelte-preprocess "^5.1.3" typescript "^5.0.3" -svelte-eslint-parser@^0.41.0: - version "0.41.0" - resolved "https://registry.yarnpkg.com/svelte-eslint-parser/-/svelte-eslint-parser-0.41.0.tgz#7d02c2314abe7dc4fe0e935bf4fcc28078c590f2" - integrity sha512-L6f4hOL+AbgfBIB52Z310pg1d2QjRqm7wy3kI1W6hhdhX5bvu7+f0R6w4ykp5HoDdzq+vGhIJmsisaiJDGmVfA== +svelte-eslint-parser@^0.43.0: + version "0.43.0" + resolved "https://registry.yarnpkg.com/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz#649e80f65183c4c1d1536d03dcb903e0632f4da4" + integrity sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA== dependencies: eslint-scope "^7.2.2" eslint-visitor-keys "^3.4.3" @@ -4241,23 +4314,23 @@ svelte-preprocess@^5.0.4, svelte-preprocess@^5.1.3: sorcery "^0.11.0" strip-indent "^3.0.0" -svelte@5.0.0-next.179: - version "5.0.0-next.179" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.0.0-next.179.tgz#5e74b02afe7ac3b8b7d5f38ab0a7bddf58472b35" - integrity sha512-z2x/RcctbQ95vNt52p/+fCJzyU2RVmK03V6thiFT/gblNHw/qONb6hZXfxfCgIsCWjm8thDcgDcmRClZj/Ging== +svelte@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.0.0.tgz#509fa4e90034a4dd8f0ee19215af373f4d3be793" + integrity sha512-jv2IvTtakG58DqZMo6fY3T6HFmGV4iDQH2lSUyfmCEYaoa+aCNcF+9rERbdDvT4XDF0nQBg6TEoJn0dirED8VQ== dependencies: - "@ampproject/remapping" "^2.2.1" - "@jridgewell/sourcemap-codec" "^1.4.15" + "@ampproject/remapping" "^2.3.0" + "@jridgewell/sourcemap-codec" "^1.5.0" "@types/estree" "^1.0.5" - acorn "^8.11.3" + acorn "^8.12.1" acorn-typescript "^1.4.13" - aria-query "^5.3.0" - axobject-query "^4.0.0" + aria-query "^5.3.1" + axobject-query "^4.1.0" esm-env "^1.0.0" esrap "^1.2.2" is-reference "^3.0.2" locate-character "^3.0.0" - magic-string "^0.30.5" + magic-string "^0.30.11" zimmerframe "^1.1.2" svgo@^3.2.0: @@ -4356,9 +4429,9 @@ tslib@^1.8.1: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.3: - version "2.7.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" - integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + version "2.8.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.0.tgz#d124c86c3c05a40a91e6fdea4021bd31d377971b" + integrity sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA== tsutils@^3.21.0: version "3.21.0" @@ -4445,11 +4518,11 @@ typescript@4.5.2: integrity sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw== typescript@^5.0.3, typescript@^5.0.4: - version "5.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" - integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== -ufo@^1.5.3: +ufo@^1.5.4: version "1.5.4" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754" integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== @@ -4469,13 +4542,13 @@ universalify@^0.2.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== -update-browserslist-db@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" - integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== dependencies: - escalade "^3.1.2" - picocolors "^1.0.1" + escalade "^3.2.0" + picocolors "^1.1.0" uri-js@^4.2.2: version "4.4.1" @@ -4527,10 +4600,10 @@ vite@=5.4.7, vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -vitefu@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/vitefu/-/vitefu-1.0.2.tgz#fbe9f7c7478be51678214bf468d7296ce29bf8ff" - integrity sha512-0/iAvbXyM3RiPPJ4lyD4w6Mjgtf4ejTK6TPvTNG3H32PLwuT0N/ZjJLiXug7ETE/LWtTeHw9WRv7uX/tIKYyKg== +vitefu@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/vitefu/-/vitefu-1.0.3.tgz#0467c75ee2be951c35246605b7fdbdbfd03b65d1" + integrity sha512-iKKfOMBHob2WxEJbqbJjHAkmYgvFDPhuqrO82om83S8RLk+17FtyMBfcyeH8GqD0ihShtkMW/zzJgiA51hCNCQ== vitest@^1.2.1: version "1.6.0" From 9649bbdcaa8b0cfd871e1178b5673fa04b19a4bb Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 26 Oct 2024 18:27:10 +1000 Subject: [PATCH 027/113] Force cookie update for CVE Sveltekit won't update until 3.0 https://github.com/sveltejs/kit/pull/12768 --- package.json | 3 ++- yarn.lock | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 87db2a0d1..33cb11aca 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,8 @@ }, "resolutions": { "canvas": "npm:empty-npm-package", - "vite": "=5.4.7" + "vite": "=5.4.7", + "cookie": "0.7.0" }, "browserslist": [ "defaults", diff --git a/yarn.lock b/yarn.lock index a0be1ad8a..a165ea588 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1589,10 +1589,10 @@ confbox@^0.1.8: resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== -cookie@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" - integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== +cookie@0.7.0, cookie@^0.6.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.0.tgz#2148f68a77245d5c2c0005d264bc3e08cfa0655d" + integrity sha512-qCf+V4dtlNhSRXGAZatc1TasyFO6GjohcOul807YOb5ik3+kQSnb4d7iajeCL8QHaJ4uZEjCgiCJerKXwdRVlQ== cross-env@^7.0.2: version "7.0.3" @@ -4175,6 +4175,7 @@ std-env@^3.5.0: integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: + name string-width-cjs version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== From 7e9da83d2c5ea71912170e355a756d6274db5ae4 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 26 Oct 2024 18:37:56 +1000 Subject: [PATCH 028/113] Update vitest and unpin vite --- package.json | 5 +- ts/licenses.json | 4 +- ts/vite.config.ts | 24 ++- yarn.lock | 450 +++++++++++++++------------------------------- 4 files changed, 168 insertions(+), 315 deletions(-) diff --git a/package.json b/package.json index 33cb11aca..e1ba40d25 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,8 @@ "tslib": "^2.0.3", "tsx": "^3.12.0", "typescript": "^5.0.4", - "vite": "=5.4.7", - "vitest": "^1.2.1" + "vite": "^5.4.10", + "vitest": "^2" }, "dependencies": { "@bufbuild/protobuf": "^1.2.1", @@ -81,7 +81,6 @@ }, "resolutions": { "canvas": "npm:empty-npm-package", - "vite": "=5.4.7", "cookie": "0.7.0" }, "browserslist": [ diff --git a/ts/licenses.json b/ts/licenses.json index e81e140ca..9d6f7d2c1 100644 --- a/ts/licenses.json +++ b/ts/licenses.json @@ -75,8 +75,8 @@ "acorn-walk@7.2.0": { "licenses": "MIT", "repository": "https://github.com/acornjs/acorn", - "path": "node_modules/acorn-globals/node_modules/acorn-walk", - "licenseFile": "node_modules/acorn-globals/node_modules/acorn-walk/LICENSE" + "path": "node_modules/acorn-walk", + "licenseFile": "node_modules/acorn-walk/LICENSE" }, "acorn@7.4.1": { "licenses": "MIT", diff --git a/ts/vite.config.ts b/ts/vite.config.ts index 8e1da60b9..233b6c8e1 100644 --- a/ts/vite.config.ts +++ b/ts/vite.config.ts @@ -3,7 +3,8 @@ import svg from "@poppanator/sveltekit-svg"; import { sveltekit } from "@sveltejs/kit/vite"; import { realpathSync } from "fs"; -import { defineConfig } from "vite"; +import { defineConfig as defineViteConfig, mergeConfig } from "vite"; +import { defineConfig as defineVitestConfig } from "vitest/config"; const configure = (proxy: any, _options: any) => { proxy.on("error", (err: any) => { @@ -17,15 +18,8 @@ const configure = (proxy: any, _options: any) => { }); }; -export default defineConfig({ +const viteConfig = defineViteConfig({ plugins: [sveltekit(), svg({})], - test: { - include: ["**/*.{test,spec}.{js,ts}"], - cache: { - // prevent vitest from creating ts/node_modules/.vitest - dir: "../node_modules/.vitest", - }, - }, build: { reportCompressedSize: false, // defaults use chrome87, but we need 77 for qt 5.14 @@ -52,3 +46,15 @@ export default defineConfig({ }, }, }); + +const vitestConfig = defineVitestConfig({ + test: { + include: ["**/*.{test,spec}.{js,ts}"], + cache: { + // prevent vitest from creating ts/node_modules/.vitest + dir: "../node_modules/.vitest", + }, + }, +}); + +export default mergeConfig(viteConfig, vitestConfig); diff --git a/yarn.lock b/yarn.lock index a165ea588..30ef084eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -385,13 +385,6 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@jest/schemas@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" - integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== - dependencies: - "@sinclair/typebox" "^0.27.8" - "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -661,11 +654,6 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@sinclair/typebox@^0.27.8": - version "0.27.8" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" - integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== - "@sqltools/formatter@^1.2.2": version "1.2.5" resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.5.tgz#3abc203c79b8c3e90fd6c156a0c62d5403520e12" @@ -1136,49 +1124,64 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@vitest/expect@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.6.0.tgz#0b3ba0914f738508464983f4d811bc122b51fb30" - integrity sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ== +"@vitest/expect@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.1.3.tgz#4b9a6fff22be4c4cd5d57e687cfda611b514b0ad" + integrity sha512-SNBoPubeCJhZ48agjXruCI57DvxcsivVDdWz+SSsmjTT4QN/DfHk3zB/xKsJqMs26bLZ/pNRLnCf0j679i0uWQ== dependencies: - "@vitest/spy" "1.6.0" - "@vitest/utils" "1.6.0" - chai "^4.3.10" + "@vitest/spy" "2.1.3" + "@vitest/utils" "2.1.3" + chai "^5.1.1" + tinyrainbow "^1.2.0" -"@vitest/runner@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.6.0.tgz#a6de49a96cb33b0e3ba0d9064a3e8d6ce2f08825" - integrity sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg== +"@vitest/mocker@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-2.1.3.tgz#a3593b426551be5715fa108faf04f8a9ddb0a9cc" + integrity sha512-eSpdY/eJDuOvuTA3ASzCjdithHa+GIF1L4PqtEELl6Qa3XafdMLBpBlZCIUCX2J+Q6sNmjmxtosAG62fK4BlqQ== dependencies: - "@vitest/utils" "1.6.0" - p-limit "^5.0.0" - pathe "^1.1.1" - -"@vitest/snapshot@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.6.0.tgz#deb7e4498a5299c1198136f56e6e0f692e6af470" - integrity sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ== - dependencies: - magic-string "^0.30.5" - pathe "^1.1.1" - pretty-format "^29.7.0" - -"@vitest/spy@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.6.0.tgz#362cbd42ccdb03f1613798fde99799649516906d" - integrity sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw== - dependencies: - tinyspy "^2.2.0" - -"@vitest/utils@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.6.0.tgz#5c5675ca7d6f546a7b4337de9ae882e6c57896a1" - integrity sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw== - dependencies: - diff-sequences "^29.6.3" + "@vitest/spy" "2.1.3" estree-walker "^3.0.3" - loupe "^2.3.7" - pretty-format "^29.7.0" + magic-string "^0.30.11" + +"@vitest/pretty-format@2.1.3", "@vitest/pretty-format@^2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.1.3.tgz#48b9b03de75507d1d493df7beb48dc39a1946a3e" + integrity sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ== + dependencies: + tinyrainbow "^1.2.0" + +"@vitest/runner@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-2.1.3.tgz#20a6da112007dfd92969951df189c6da66c9dac4" + integrity sha512-JGzpWqmFJ4fq5ZKHtVO3Xuy1iF2rHGV4d/pdzgkYHm1+gOzNZtqjvyiaDGJytRyMU54qkxpNzCx+PErzJ1/JqQ== + dependencies: + "@vitest/utils" "2.1.3" + pathe "^1.1.2" + +"@vitest/snapshot@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-2.1.3.tgz#1b405a9c40a82563605b13fdc045217751069e58" + integrity sha512-qWC2mWc7VAXmjAkEKxrScWHWFyCQx/cmiZtuGqMi+WwqQJ2iURsVY4ZfAK6dVo6K2smKRU6l3BPwqEBvhnpQGg== + dependencies: + "@vitest/pretty-format" "2.1.3" + magic-string "^0.30.11" + pathe "^1.1.2" + +"@vitest/spy@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.1.3.tgz#2c8a457673094ec4c1ab7c50cb11c58e3624ada2" + integrity sha512-Nb2UzbcUswzeSP7JksMDaqsI43Sj5+Kry6ry6jQJT4b5gAK+NS9NED6mDb8FlMRCX8m5guaHCDZmqYMMWRy5nQ== + dependencies: + tinyspy "^3.0.0" + +"@vitest/utils@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.1.3.tgz#e52aa5745384091b151cbdf79bb5a3ad2bea88d2" + integrity sha512-xpiVfDSg1RrYT0tX6czgerkpcKFmFOF/gCr30+Mve5V2kewCy4Prn1/NDMSRwaSmT7PRaOF83wu+bEtsY1wrvA== + dependencies: + "@vitest/pretty-format" "2.1.3" + loupe "^3.1.1" + tinyrainbow "^1.2.0" abab@^2.0.5, abab@^2.0.6: version "2.0.6" @@ -1213,19 +1216,12 @@ acorn-walk@^7.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn-walk@^8.3.2: - version "8.3.4" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" - integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== - dependencies: - acorn "^8.11.0" - acorn@^7.1.1: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.11.0, acorn@^8.12.1, acorn@^8.5.0, acorn@^8.9.0: +acorn@^8.12.1, acorn@^8.5.0, acorn@^8.9.0: version "8.13.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== @@ -1264,11 +1260,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - ansi-styles@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" @@ -1368,10 +1359,10 @@ arraybuffer.prototype.slice@^1.0.3: is-array-buffer "^3.0.4" is-shared-array-buffer "^1.0.2" -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== ast-metadata-inferer@^0.8.0: version "0.8.0" @@ -1500,18 +1491,16 @@ canvas@^2.8.0, "canvas@npm:empty-npm-package": resolved "https://registry.yarnpkg.com/empty-npm-package/-/empty-npm-package-1.0.0.tgz#fda29eb6de5efa391f73d578697853af55f6793a" integrity sha512-q4Mq/+XO7UNDdMiPpR/LIBIW1Zl4V0Z6UT9aKGqIAnBCtCb3lvZJM1KbDbdzdC8fKflwflModfjR29Nt0EpcwA== -chai@^4.3.10: - version "4.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" - integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== +chai@^5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.1.2.tgz#3afbc340b994ae3610ca519a6c70ace77ad4378d" + integrity sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw== dependencies: - assertion-error "^1.1.0" - check-error "^1.0.3" - deep-eql "^4.1.3" - get-func-name "^2.0.2" - loupe "^2.3.6" - pathval "^1.1.1" - type-detect "^4.1.0" + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" chalk@4.1.2, chalk@^4.0.0: version "4.1.2" @@ -1521,12 +1510,10 @@ chalk@4.1.2, chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -check-error@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" - integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== - dependencies: - get-func-name "^2.0.2" +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== "chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1: version "3.6.0" @@ -1584,11 +1571,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -confbox@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" - integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== - cookie@0.7.0, cookie@^0.6.0: version "0.7.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.0.tgz#2148f68a77245d5c2c0005d264bc3e08cfa0655d" @@ -1601,7 +1583,7 @@ cross-env@^7.0.2: dependencies: cross-spawn "^7.0.1" -cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1951,7 +1933,7 @@ data-view-byte-offset@^1.0.0: es-errors "^1.3.0" is-data-view "^1.0.1" -debug@4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7: +debug@4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== @@ -1970,12 +1952,10 @@ decimal.js@^10.3.1: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== -deep-eql@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" - integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== - dependencies: - type-detect "^4.0.0" +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== deep-is@^0.1.3: version "0.1.4" @@ -2032,11 +2012,6 @@ devalue@^5.1.0: resolved "https://registry.yarnpkg.com/devalue/-/devalue-5.1.1.tgz#a71887ac0f354652851752654e4bd435a53891ae" integrity sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw== -diff-sequences@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" - integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== - diff@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" @@ -2544,21 +2519,6 @@ esutils@^2.0.2, esutils@^2.0.3: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -execa@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" - integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^8.0.1" - human-signals "^5.0.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^4.1.0" - strip-final-newline "^3.0.0" - fabric@^5.3.0: version "5.4.0" resolved "https://registry.yarnpkg.com/fabric/-/fabric-5.4.0.tgz#314d0b31e6ae0c4b2b097dc5ed7fb0bd57cc79e5" @@ -2690,11 +2650,6 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -get-func-name@^2.0.1, get-func-name@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" - integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== - get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" @@ -2706,11 +2661,6 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" -get-stream@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" - integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== - get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" @@ -2896,11 +2846,6 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -human-signals@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" - integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== - iconv-lite@0.6, iconv-lite@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -3090,11 +3035,6 @@ is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: dependencies: call-bind "^1.0.7" -is-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" - integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== - is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -3154,11 +3094,6 @@ jquery-ui-dist@^1.12.1: resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de" integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg== -js-tokens@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.0.tgz#0f893996d6f3ed46df7f0a3b12a03f5fd84223c1" - integrity sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ== - js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -3273,14 +3208,6 @@ lilconfig@^2.0.5: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== -local-pkg@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.0.tgz#093d25a346bae59a99f80e75f6e9d36d7e8c925c" - integrity sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg== - dependencies: - mlly "^1.4.2" - pkg-types "^1.0.3" - locate-character@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-3.0.0.tgz#0305c5b8744f61028ef5d01f444009e00779f974" @@ -3313,12 +3240,10 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -loupe@^2.3.6, loupe@^2.3.7: - version "2.3.7" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" - integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== - dependencies: - get-func-name "^2.0.1" +loupe@^3.1.0, loupe@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.2.tgz#c86e0696804a02218f2206124c45d8b15291a240" + integrity sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg== lru-cache@^10.2.0: version "10.4.3" @@ -3357,11 +3282,6 @@ mdn-data@2.0.30: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -3387,11 +3307,6 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" -mimic-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== - min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -3433,16 +3348,6 @@ mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mlly@^1.4.2, mlly@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.2.tgz#21c0d04543207495b8d867eff0ac29fac9a023c0" - integrity sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA== - dependencies: - acorn "^8.12.1" - pathe "^1.1.2" - pkg-types "^1.2.0" - ufo "^1.5.4" - mri@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" @@ -3510,13 +3415,6 @@ npm-normalize-package-bin@^3.0.0: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== -npm-run-path@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" - integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== - dependencies: - path-key "^4.0.0" - nth-check@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" @@ -3584,13 +3482,6 @@ once@^1.3.0: dependencies: wrappy "1" -onetime@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" - integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== - dependencies: - mimic-fn "^4.0.0" - optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -3610,13 +3501,6 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-limit@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985" - integrity sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ== - dependencies: - yocto-queue "^1.0.0" - p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -3656,11 +3540,6 @@ path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-key@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" - integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== - path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -3679,15 +3558,15 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pathe@^1.1.1, pathe@^1.1.2: +pathe@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== +pathval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" + integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== picocolors@^1.0.0, picocolors@^1.1.0: version "1.1.1" @@ -3704,15 +3583,6 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== -pkg-types@^1.0.3, pkg-types@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.2.1.tgz#6ac4e455a5bb4b9a6185c1c79abd544c901db2e5" - integrity sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw== - dependencies: - confbox "^0.1.8" - mlly "^1.7.2" - pathe "^1.1.2" - possible-typed-array-names@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" @@ -3768,15 +3638,6 @@ prettier@^2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -pretty-format@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" - integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== - dependencies: - "@jest/schemas" "^29.6.3" - ansi-styles "^5.0.0" - react-is "^18.0.0" - psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -3797,11 +3658,6 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -react-is@^18.0.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" - integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== - read-installed-packages@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/read-installed-packages/-/read-installed-packages-2.0.1.tgz#8ba63a9382a5158c37a288c2f21268d6eb9c85eb" @@ -4063,7 +3919,7 @@ siginfo@^2.0.0: resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== -signal-exit@^4.0.1, signal-exit@^4.1.0: +signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== @@ -4169,7 +4025,7 @@ stackback@0.0.2: resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== -std-env@^3.5.0: +std-env@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== @@ -4240,11 +4096,6 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-final-newline@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" - integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== - strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" @@ -4257,13 +4108,6 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strip-literal@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.1.0.tgz#6d82ade5e2e74f5c7e8739b6c84692bd65f0bd2a" - integrity sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw== - dependencies: - js-tokens "^9.0.0" - supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -4365,20 +4209,30 @@ tiny-glob@^0.2.9: globalyzer "0.1.0" globrex "^0.1.2" -tinybench@^2.5.1: +tinybench@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== -tinypool@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.4.tgz#e217fe1270d941b39e98c625dcecebb1408c9aa8" - integrity sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ== +tinyexec@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.1.tgz#0ab0daf93b43e2c211212396bdb836b468c97c98" + integrity sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ== -tinyspy@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.1.tgz#117b2342f1f38a0dbdcc73a50a454883adf861d1" - integrity sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A== +tinypool@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.0.1.tgz#c64233c4fac4304e109a64340178760116dbe1fe" + integrity sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA== + +tinyrainbow@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-1.2.0.tgz#5c57d2fc0fb3d1afd78465c33ca885d04f02abb5" + integrity sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ== + +tinyspy@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" + integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== to-regex-range@^5.0.1: version "5.0.1" @@ -4459,11 +4313,6 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@^4.0.0, type-detect@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" - integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== - type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" @@ -4523,11 +4372,6 @@ typescript@^5.0.3, typescript@^5.0.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== -ufo@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754" - integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== - unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" @@ -4579,18 +4423,17 @@ validate-npm-package-license@^3.0.4: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -vite-node@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.0.tgz#2c7e61129bfecc759478fa592754fd9704aaba7f" - integrity sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw== +vite-node@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-2.1.3.tgz#8291d31f91c69dc22fea7909f4394c2b3cc2e2d9" + integrity sha512-I1JadzO+xYX887S39Do+paRePCKoiDrWRRjp9kkG5he0t7RXNvPAJPCQSJqbGN4uCrFFeS3Kj3sLqY8NMYBEdA== dependencies: cac "^6.7.14" - debug "^4.3.4" - pathe "^1.1.1" - picocolors "^1.0.0" + debug "^4.3.6" + pathe "^1.1.2" vite "^5.0.0" -vite@=5.4.7, vite@^5.0.0: +vite@^5.0.0: version "5.4.7" resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.7.tgz#d226f57c08b61379e955f3836253ed3efb2dcf00" integrity sha512-5l2zxqMEPVENgvzTuBpHer2awaetimj2BGkhBPdnwKbPNOlHsODU+oiazEZzLK7KhAnOrO+XGYJYn4ZlUhDtDQ== @@ -4601,36 +4444,46 @@ vite@=5.4.7, vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" +vite@^5.4.10: + version "5.4.10" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.10.tgz#d358a7bd8beda6cf0f3b7a450a8c7693a4f80c18" + integrity sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.43" + rollup "^4.20.0" + optionalDependencies: + fsevents "~2.3.3" + vitefu@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/vitefu/-/vitefu-1.0.3.tgz#0467c75ee2be951c35246605b7fdbdbfd03b65d1" integrity sha512-iKKfOMBHob2WxEJbqbJjHAkmYgvFDPhuqrO82om83S8RLk+17FtyMBfcyeH8GqD0ihShtkMW/zzJgiA51hCNCQ== -vitest@^1.2.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.6.0.tgz#9d5ad4752a3c451be919e412c597126cffb9892f" - integrity sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA== +vitest@^2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-2.1.3.tgz#dae1055dd328621b59fc6e594fd988fbf2e5370e" + integrity sha512-Zrxbg/WiIvUP2uEzelDNTXmEMJXuzJ1kCpbDvaKByFA9MNeO95V+7r/3ti0qzJzrxdyuUw5VduN7k+D3VmVOSA== dependencies: - "@vitest/expect" "1.6.0" - "@vitest/runner" "1.6.0" - "@vitest/snapshot" "1.6.0" - "@vitest/spy" "1.6.0" - "@vitest/utils" "1.6.0" - acorn-walk "^8.3.2" - chai "^4.3.10" - debug "^4.3.4" - execa "^8.0.1" - local-pkg "^0.5.0" - magic-string "^0.30.5" - pathe "^1.1.1" - picocolors "^1.0.0" - std-env "^3.5.0" - strip-literal "^2.0.0" - tinybench "^2.5.1" - tinypool "^0.8.3" + "@vitest/expect" "2.1.3" + "@vitest/mocker" "2.1.3" + "@vitest/pretty-format" "^2.1.3" + "@vitest/runner" "2.1.3" + "@vitest/snapshot" "2.1.3" + "@vitest/spy" "2.1.3" + "@vitest/utils" "2.1.3" + chai "^5.1.1" + debug "^4.3.6" + magic-string "^0.30.11" + pathe "^1.1.2" + std-env "^3.7.0" + tinybench "^2.9.0" + tinyexec "^0.3.0" + tinypool "^1.0.0" + tinyrainbow "^1.2.0" vite "^5.0.0" - vite-node "1.6.0" - why-is-node-running "^2.2.2" + vite-node "2.1.3" + why-is-node-running "^2.3.0" w3c-hr-time@^1.0.2: version "1.0.2" @@ -4708,7 +4561,7 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -why-is-node-running@^2.2.2: +why-is-node-running@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== @@ -4769,11 +4622,6 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -yocto-queue@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.1.1.tgz#fef65ce3ac9f8a32ceac5a634f74e17e5b232110" - integrity sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g== - zimmerframe@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/zimmerframe/-/zimmerframe-1.1.2.tgz#5b75f1fa83b07ae2a428d51e50f58e2ae6855e5e" From fe0f5370b0978f2e4f357d9612eaadde36e1d0bf Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 26 Oct 2024 18:50:02 +1000 Subject: [PATCH 029/113] Revert "Fix ease button alignment (#3474)" (#3522) This reverts commit 569a4705e71173c887d0ac6b13d3614b6189e989. --- qt/aqt/data/web/css/reviewer-bottom.scss | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/qt/aqt/data/web/css/reviewer-bottom.scss b/qt/aqt/data/web/css/reviewer-bottom.scss index ac07d4d80..59098a5fb 100644 --- a/qt/aqt/data/web/css/reviewer-bottom.scss +++ b/qt/aqt/data/web/css/reviewer-bottom.scss @@ -23,16 +23,6 @@ body { position: relative; } -#innertable > tbody > tr { - display: flex; - align-items: stretch; - justify-content: center; -} - -#innertable > tbody > tr > td { - flex: 1; -} - button { min-width: 60px; white-space: nowrap; From 7500beaba3c36021d0aeb3aafb46f80c18cebf29 Mon Sep 17 00:00:00 2001 From: user1823 <92206575+user1823@users.noreply.github.com> Date: Sat, 26 Oct 2024 14:35:01 +0530 Subject: [PATCH 030/113] Fix calculation of daily load (#3516) * Fix calculation of daily load * Daily load in reviews/day --- rslib/src/stats/graphs/future_due.rs | 7 ++----- ts/routes/graphs/future-due.ts | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/rslib/src/stats/graphs/future_due.rs b/rslib/src/stats/graphs/future_due.rs index 2b7caec5e..3c0194a38 100644 --- a/rslib/src/stats/graphs/future_due.rs +++ b/rslib/src/stats/graphs/future_due.rs @@ -26,17 +26,14 @@ impl GraphsContext { due - (self.days_elapsed as i32) }; + daily_load += 1.0 / c.interval.max(1) as f32; + // still want to filtered out buried cards that are due today if due_day == 0 && matches!(c.queue, CardQueue::UserBuried | CardQueue::SchedBuried) { continue; } have_backlog |= due_day < 0; *due_by_day.entry(due_day).or_default() += 1; - if matches!(c.queue, CardQueue::Review | CardQueue::DayLearn) { - daily_load += 1.0 / c.interval.max(1) as f32; - } else { - daily_load += 1.0; - } } FutureDue { future_due: due_by_day, diff --git a/ts/routes/graphs/future-due.ts b/ts/routes/graphs/future-due.ts index b965874c5..96a7bab7a 100644 --- a/ts/routes/graphs/future-due.ts +++ b/ts/routes/graphs/future-due.ts @@ -145,8 +145,8 @@ export function buildHistogram( }, { label: tr.statisticsDailyLoad(), - value: tr.statisticsReviews({ - reviews: sourceData.dailyLoad, + value: tr.statisticsReviewsPerDay({ + count: sourceData.dailyLoad, }), }, ]; From 939cc5a268108eb518ebfeff3c9a21b3bb57be8b Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Sat, 26 Oct 2024 17:09:20 +0800 Subject: [PATCH 031/113] Fix/skip suspended cards in graphs context retrievability (#3518) * skip suspended cards in GraphsContext retrievability * avoid i32 overflow * avoid u32 overflow --- rslib/src/browser_table.rs | 10 +++++----- rslib/src/stats/graphs/retrievability.rs | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/rslib/src/browser_table.rs b/rslib/src/browser_table.rs index 19fdb11f6..46a64f434 100644 --- a/rslib/src/browser_table.rs +++ b/rslib/src/browser_table.rs @@ -115,8 +115,8 @@ impl Card { } else if self.is_due_in_days() { Some( TimestampSecs::now().adding_secs( - ((self.original_or_current_due() - timing.days_elapsed as i32) - .saturating_mul(86400)) as i64, + (self.original_or_current_due() as i64 - timing.days_elapsed as i64) + .saturating_mul(86400), ), ) } else { @@ -131,9 +131,9 @@ impl Card { Some((timing.next_day_at.0 as u32).saturating_sub(self.due.max(0) as u32) / 86_400) } else { self.due_time(timing).map(|due| { - due.adding_secs(-86_400 * self.interval as i64) - .elapsed_secs() as u32 - / 86_400 + (due.adding_secs(-86_400 * self.interval as i64) + .elapsed_secs() + / 86_400) as u32 }) } } diff --git a/rslib/src/stats/graphs/retrievability.rs b/rslib/src/stats/graphs/retrievability.rs index 930a21c5b..2c47830e3 100644 --- a/rslib/src/stats/graphs/retrievability.rs +++ b/rslib/src/stats/graphs/retrievability.rs @@ -4,6 +4,7 @@ use anki_proto::stats::graphs_response::Retrievability; use fsrs::FSRS; +use crate::card::CardQueue; use crate::scheduler::timing::SchedTimingToday; use crate::stats::graphs::eases::percent_to_bin; use crate::stats::graphs::GraphsContext; @@ -23,6 +24,9 @@ impl GraphsContext { let mut note_retrievability: std::collections::HashMap = std::collections::HashMap::new(); for card in &self.cards { + if card.queue == CardQueue::Suspended { + continue; + } let entry = note_retrievability .entry(card.note_id.0) .or_insert((0.0, 0)); From 507050c8764432801d7b8f86ee73783be026f823 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Sat, 26 Oct 2024 02:33:53 -0700 Subject: [PATCH 032/113] Enable strict_optional for aqt/preferences.py (#3519) * Enable strict_optional for aqt/preferences.py * Fix mypy errors --- .mypy.ini | 2 ++ qt/aqt/preferences.py | 25 ++++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index 5d6d2be5c..3f293ef28 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -40,6 +40,8 @@ strict_optional = True strict_optional = True [mypy-aqt.editor] strict_optional = True +[mypy-aqt.preferences] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py index 3676fe169..aef3dc818 100644 --- a/qt/aqt/preferences.py +++ b/qt/aqt/preferences.py @@ -46,13 +46,16 @@ class Preferences(QDialog): self.form.network_timeout, ): spinbox.setSuffix(f" {spinbox.suffix()}") + disable_help_button(self) - self.form.buttonBox.button(QDialogButtonBox.StandardButton.Help).setAutoDefault( - False - ) - self.form.buttonBox.button( - QDialogButtonBox.StandardButton.Close - ).setAutoDefault(False) + help_button = self.form.buttonBox.button(QDialogButtonBox.StandardButton.Help) + assert help_button is not None + help_button.setAutoDefault(False) + + close_button = self.form.buttonBox.button(QDialogButtonBox.StandardButton.Close) + assert close_button is not None + close_button.setAutoDefault(False) + qconnect( self.form.buttonBox.helpRequested, lambda: openHelp(HelpPage.PREFERENCES) ) @@ -218,6 +221,7 @@ class Preferences(QDialog): qconnect(self.form.syncAnkiHubLogin.clicked, self.ankihub_sync_login) def update_login_status(self) -> None: + assert self.prof is not None if not self.prof.get("syncKey"): self.form.syncUser.setText(tr.preferences_ankiweb_intro()) self.form.syncLogin.setVisible(True) @@ -241,6 +245,7 @@ class Preferences(QDialog): def sync_login(self) -> None: def on_success(): + assert self.prof is not None if self.prof.get("syncKey"): self.update_login_status() self.confirm_sync_after_login() @@ -251,6 +256,7 @@ class Preferences(QDialog): if self.mw.media_syncer.is_syncing(): showWarning("Can't log out while sync in progress.") return + assert self.prof is not None self.prof["syncKey"] = None self.mw.col.media.force_resync() self.update_login_status() @@ -263,7 +269,10 @@ class Preferences(QDialog): ankihub_login(self.mw, on_success) def ankihub_sync_logout(self) -> None: - ankihub_logout(self.mw, self.update_login_status, self.mw.pm.ankihub_token()) + ankihub_token = self.mw.pm.ankihub_token() + if ankihub_token is None: + return + ankihub_logout(self.mw, self.update_login_status, ankihub_token) def confirm_sync_after_login(self) -> None: from aqt import mw @@ -272,6 +281,7 @@ class Preferences(QDialog): self.accept_with_callback(self.mw.on_sync_button_clicked) def update_network(self) -> None: + assert self.prof is not None self.prof["autoSync"] = self.form.syncOnProgramOpen.isChecked() self.prof["syncMedia"] = self.form.syncMedia.isChecked() self.mw.pm.set_periodic_sync_media_minutes( @@ -378,6 +388,7 @@ class Preferences(QDialog): self.mw.set_theme(Theme(index)) def on_reset_window_sizes(self) -> None: + assert self.prof is not None regexp = re.compile(r"(Geom(etry)?|State|Splitter|Header)(\d+.\d+)?$") for key in list(self.prof.keys()): if regexp.search(key): From 5caeac530eec7279e330ffe45a0572f6a357fd39 Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Sat, 26 Oct 2024 17:36:27 +0800 Subject: [PATCH 033/113] Update to FSRS-rs v1.3.5 (FSRS-5 model update) && keep three decimals for stability (#3520) * Update to FSRS-rs v1.3.5 (FSRS-5 model update) * keep three decimals for stability fix https://forums.ankiweb.net/t/fsrs-5-1d-scheduling-and-learning-steps/50242/122?u=l.m.sherlock --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- cargo/licenses.json | 2 +- rslib/src/storage/card/data.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1385d889c..2393ff6f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1860,9 +1860,9 @@ dependencies = [ [[package]] name = "fsrs" -version = "1.3.4" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a05b1fdbaa34f9bcd605ad50477eea51b27b3f60f973021bd9ee1b5943169150" +checksum = "42155527199b3e7b6ad47e9db849ee25bd5bd436ee17a72ae0a3de646a20021a" dependencies = [ "burn", "itertools 0.12.1", diff --git a/Cargo.toml b/Cargo.toml index 4af2c46d1..c3d6241f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ git = "https://github.com/ankitects/linkcheck.git" rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca" [workspace.dependencies.fsrs] -version = "=1.3.4" +version = "=1.3.5" # git = "https://github.com/open-spaced-repetition/fsrs-rs.git" # rev = "58ca25ed2bc4bb1dc376208bbcaed7f5a501b941" # path = "../open-spaced-repetition/fsrs-rs" diff --git a/cargo/licenses.json b/cargo/licenses.json index de342bec6..cbbede5ca 100644 --- a/cargo/licenses.json +++ b/cargo/licenses.json @@ -1225,7 +1225,7 @@ }, { "name": "fsrs", - "version": "1.3.4", + "version": "1.3.5", "authors": "Open Spaced Repetition", "repository": "https://github.com/open-spaced-repetition/fsrs-rs", "license": "BSD-3-Clause", diff --git a/rslib/src/storage/card/data.rs b/rslib/src/storage/card/data.rs index bbce38bb6..ea529c495 100644 --- a/rslib/src/storage/card/data.rs +++ b/rslib/src/storage/card/data.rs @@ -79,7 +79,7 @@ impl CardData { pub(crate) fn convert_to_json(&mut self) -> Result { if let Some(v) = &mut self.fsrs_stability { - round_to_places(v, 2) + round_to_places(v, 3) } if let Some(v) = &mut self.fsrs_difficulty { round_to_places(v, 3) @@ -163,7 +163,7 @@ mod test { }; assert_eq!( data.convert_to_json().unwrap(), - r#"{"s":123.46,"d":1.235,"dr":0.99}"# + r#"{"s":123.457,"d":1.235,"dr":0.99}"# ); } } From 9a44881121f78d5b06e9abe1c719d5b3db47e15b Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Sat, 26 Oct 2024 17:38:17 +0800 Subject: [PATCH 034/113] export revlogs where the rating is between 1 and 4 for research (#3524) --- rslib/src/scheduler/fsrs/params.rs | 2 +- rslib/src/storage/revlog/mod.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/rslib/src/scheduler/fsrs/params.rs b/rslib/src/scheduler/fsrs/params.rs index 1bedf4ffc..d31e2aa86 100644 --- a/rslib/src/scheduler/fsrs/params.rs +++ b/rslib/src/scheduler/fsrs/params.rs @@ -129,7 +129,7 @@ impl Collection { /// Used for exporting revlogs for algorithm research. pub fn export_dataset(&mut self, min_entries: usize, target_path: &Path) -> Result<()> { - let revlog_entries = self.storage.get_all_revlog_entries_in_card_order()?; + let revlog_entries = self.storage.get_revlog_entries_for_export_dataset()?; if revlog_entries.len() < min_entries { return Err(AnkiError::FsrsInsufficientData); } diff --git a/rslib/src/storage/revlog/mod.rs b/rslib/src/storage/revlog/mod.rs index 84332b0d0..c6ff49271 100644 --- a/rslib/src/storage/revlog/mod.rs +++ b/rslib/src/storage/revlog/mod.rs @@ -154,6 +154,17 @@ impl SqliteStorage { .collect() } + pub(crate) fn get_revlog_entries_for_export_dataset(&self) -> Result> { + self.db + .prepare_cached(concat!( + include_str!("get.sql"), + " where ease between 1 and 4", + " order by cid, id" + ))? + .query_and_then([], row_to_revlog_entry)? + .collect() + } + pub(crate) fn get_all_revlog_entries_in_card_order(&self) -> Result> { self.db .prepare_cached(concat!(include_str!("get.sql"), " order by cid, id"))? From 1aa734ad282eb7d1c1a59240ca57831ca9598807 Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Sat, 26 Oct 2024 17:38:37 +0800 Subject: [PATCH 035/113] Fix/set default easyDaysPercentages when switch preset (#3526) --- ts/routes/deck-options/EasyDays.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/routes/deck-options/EasyDays.svelte b/ts/routes/deck-options/EasyDays.svelte index cfa0c85fa..7ca4fdf56 100644 --- a/ts/routes/deck-options/EasyDays.svelte +++ b/ts/routes/deck-options/EasyDays.svelte @@ -15,7 +15,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html const config = state.currentConfig; const defaults = state.defaults; - if ($config.easyDaysPercentages.length !== 7) { + $: if ($config.easyDaysPercentages.length !== 7) { $config.easyDaysPercentages = defaults.easyDaysPercentages; } From eacd5bf908e3e02124a12479e12bb936c09eafda Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Sat, 26 Oct 2024 17:42:57 +0800 Subject: [PATCH 036/113] Feat/add a toggle in the simulator to display time or review count (#3523) Co-authored-by: Damien Elmes --- ts/routes/deck-options/FsrsOptions.svelte | 46 ++++++++++++++++++----- ts/routes/graphs/simulator.ts | 17 ++++++--- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/ts/routes/deck-options/FsrsOptions.svelte b/ts/routes/deck-options/FsrsOptions.svelte index 1c1574791..28401169c 100644 --- a/ts/routes/deck-options/FsrsOptions.svelte +++ b/ts/routes/deck-options/FsrsOptions.svelte @@ -40,6 +40,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import NoDataOverlay from "../graphs/NoDataOverlay.svelte"; import TableData from "../graphs/TableData.svelte"; import { defaultGraphBounds, type TableDatum } from "../graphs/graph-helpers"; + import InputBox from "../graphs/InputBox.svelte"; export let state: DeckOptionsState; export let openHelpModal: (String) => void; @@ -73,6 +74,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html | ComputeRetentionProgress | undefined; + let showTime = false; + const optimalRetentionRequest = new ComputeOptimalRetentionRequest({ daysToSimulate: 365, lossAversion: 2.5, @@ -305,6 +308,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html return result; } + function addArrays(arr1: number[], arr2: number[]): number[] { + return arr1.map((value, index) => value + arr2[index]); + } + $: simulateProgressString = ""; async function simulateFsrs(): Promise { @@ -328,23 +335,37 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html resp.dailyTimeCost, Math.ceil(simulateFsrsRequest.daysToSimulate / 50), ); + const dailyReviewCount = movingAverage( + addArrays(resp.dailyReviewCount, resp.dailyNewCount), + Math.ceil(simulateFsrsRequest.daysToSimulate / 50), + ); points = points.concat( dailyTimeCost.map((v, i) => ({ x: i, - y: v, + timeCost: v, + count: dailyReviewCount[i], label: simulationNumber, })), ); - tableData = renderSimulationChart(svg as SVGElement, bounds, points); + tableData = renderSimulationChart( + svg as SVGElement, + bounds, + points, + showTime, + ); } } } + $: tableData = renderSimulationChart(svg as SVGElement, bounds, points, showTime); + function clearSimulation(): void { points = points.filter((p) => p.label !== simulationNumber); simulationNumber = Math.max(0, simulationNumber - 1); - tableData = renderSimulationChart(svg as SVGElement, bounds, points); + tableData = renderSimulationChart(svg as SVGElement, bounds, points, showTime); } + + const label = tr.statisticsReviewsTimeCheckbox(); openHelpModal("simulateFsrsReview")}> - Days to simulate + {tr.deckConfigDaysToSimulate()} @@ -491,10 +512,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html bind:value={simulateFsrsRequest.newLimit} defaultValue={defaults.newPerDay} min={0} - max={1000} + max={9999} > openHelpModal("simulateFsrsReview")}> - New cards/day + {tr.schedulingNewCardsday()} @@ -502,10 +523,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html bind:value={simulateFsrsRequest.reviewLimit} defaultValue={defaults.reviewsPerDay} min={0} - max={1000} + max={9999} > openHelpModal("simulateFsrsReview")}> - Maximum reviews/day + {tr.schedulingMaximumReviewsday()} @@ -516,7 +537,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html max={36500} > openHelpModal("simulateFsrsReview")}> - Maximum interval + {tr.schedulingMaximumInterval()} @@ -538,6 +559,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{simulateProgressString}
+ + + + diff --git a/ts/routes/graphs/simulator.ts b/ts/routes/graphs/simulator.ts index 1ebd0a4ae..db26cf65c 100644 --- a/ts/routes/graphs/simulator.ts +++ b/ts/routes/graphs/simulator.ts @@ -16,6 +16,7 @@ import { select, } from "d3"; +import * as tr from "@generated/ftl"; import { timeSpan } from "@tslib/time"; import type { GraphBounds, TableDatum } from "./graph-helpers"; import { setDataAvailable } from "./graph-helpers"; @@ -23,7 +24,8 @@ import { hideTooltip, showTooltip } from "./tooltip-utils.svelte"; export interface Point { x: number; - y: number; + timeCost: number; + count: number; label: number; } @@ -31,6 +33,7 @@ export function renderSimulationChart( svgElem: SVGElement, bounds: GraphBounds, data: Point[], + showTime: boolean, ): TableDatum[] { const svg = select(svgElem); svg.selectAll(".lines").remove(); @@ -62,10 +65,10 @@ export function renderSimulationChart( // y scale const yTickFormat = (n: number): string => { - return timeSpan(n, true); + return showTime ? timeSpan(n, true) : n.toString(); }; - const yMax = max(convertedData, d => d.y)!; + const yMax = showTime ? max(convertedData, d => d.timeCost)! : max(convertedData, d => d.count)!; const y = scaleLinear() .range([bounds.height - bounds.marginBottom, bounds.marginTop]) .domain([0, yMax]) @@ -91,10 +94,10 @@ export function renderSimulationChart( .attr("dy", "1em") .attr("fill", "currentColor") .style("text-anchor", "middle") - .text("Review Time per day"); + .text(showTime ? "Review Time per day" : "Review Count per day"); // x lines - const points = convertedData.map((d) => [x(d.date), y(d.y), d.label]); + const points = convertedData.map((d) => [x(d.date), y(showTime ? d.timeCost : d.count), d.label]); const groups = rollup(points, v => Object.assign(v, { z: v[0][2] }), d => d[2]); const color = schemeCategory10; @@ -161,7 +164,9 @@ export function renderSimulationChart( const days = +((date.getTime() - Date.now()) / (60 * 60 * 24 * 1000)).toFixed(); let tooltipContent = `Date: ${localizedDate(date)}
In ${days} Days
`; for (const [key, value] of Object.entries(groupData)) { - tooltipContent += `#${key}: ${timeSpan(value)}
`; + tooltipContent += `#${key}: ${ + showTime ? timeSpan(value) : tr.statisticsReviews({ reviews: Math.round(value) }) + }
`; } showTooltip(tooltipContent, event.pageX, event.pageY); From 97b729c5d4110148da6de4b4d8014644c4b63505 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 26 Oct 2024 19:48:48 +1000 Subject: [PATCH 037/113] Fix another non reactive property warning I waited for the PR check to pass first, but it failed to catch this, presumably as newly-added files don't trigger the existing checks to re-run. --- ts/routes/deck-options/EasyDays.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/ts/routes/deck-options/EasyDays.svelte b/ts/routes/deck-options/EasyDays.svelte index 7ca4fdf56..c87c6aba8 100644 --- a/ts/routes/deck-options/EasyDays.svelte +++ b/ts/routes/deck-options/EasyDays.svelte @@ -15,6 +15,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html const config = state.currentConfig; const defaults = state.defaults; + // svelte-ignore reactive_declaration_non_reactive_property $: if ($config.easyDaysPercentages.length !== 7) { $config.easyDaysPercentages = defaults.easyDaysPercentages; } From e4eaaa57ab6c5c833122376dbe9b9e80cce06f17 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Sat, 26 Oct 2024 02:56:34 -0700 Subject: [PATCH 038/113] Enable strict_optional for aqt/importing.py (#3527) * Enable strict_optional * Fix mypy errors --- .mypy.ini | 2 ++ qt/aqt/importing.py | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index 3f293ef28..4a9cd17f4 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -40,6 +40,8 @@ strict_optional = True strict_optional = True [mypy-aqt.editor] strict_optional = True +[mypy-aqt.importing] +strict_optional = True [mypy-aqt.preferences] strict_optional = True [mypy-anki.scheduler.base] diff --git a/qt/aqt/importing.py b/qt/aqt/importing.py index b4a73b553..985c02a8a 100644 --- a/qt/aqt/importing.py +++ b/qt/aqt/importing.py @@ -60,7 +60,7 @@ class ChangeMap(QDialog): self.frm.fields.setCurrentRow(n + 1) self.field: str | None = None - def getField(self) -> str: + def getField(self) -> str | None: self.exec() return self.field @@ -91,8 +91,10 @@ class ImportDialog(QDialog): self.importer = importer self.frm = aqt.forms.importing.Ui_ImportDialog() self.frm.setupUi(self) + help_button = self.frm.buttonBox.button(QDialogButtonBox.StandardButton.Help) + assert help_button is not None qconnect( - self.frm.buttonBox.button(QDialogButtonBox.StandardButton.Help).clicked, + help_button.clicked, self.helpRequested, ) disable_help_button(self) @@ -103,6 +105,7 @@ class ImportDialog(QDialog): gui_hooks.current_note_type_did_change.append(self.modelChanged) qconnect(self.frm.autoDetect.clicked, self.onDelimiter) self.updateDelimiterButtonText() + assert self.mw.pm.profile is not None self.frm.allowHTML.setChecked(self.mw.pm.profile.get("allowHTML", True)) qconnect(self.frm.importMode.currentIndexChanged, self.importModeChanged) self.frm.importMode.setCurrentIndex(self.mw.pm.profile.get("importMode", 1)) @@ -187,6 +190,7 @@ class ImportDialog(QDialog): showWarning(tr.importing_the_first_field_of_the_note()) return self.importer.importMode = self.frm.importMode.currentIndex() + assert self.mw.pm.profile is not None self.mw.pm.profile["importMode"] = self.importer.importMode self.importer.allowHTML = self.frm.allowHTML.isChecked() self.mw.pm.profile["allowHTML"] = self.importer.allowHTML From 0513940305ffd771d08d627a8e8c49cd58fabd5b Mon Sep 17 00:00:00 2001 From: "a.r" <887320+twwn@users.noreply.github.com> Date: Sat, 26 Oct 2024 11:58:52 +0200 Subject: [PATCH 039/113] template_filters: make {{type:}} forwards compatible (#3525) Make Anki treat {{type:unknown:field}} field replacements as {{type:field}} instead of {{field}}. The previous behavior was seriously inconvenient for several reasons, including: * Updated client aren't all released at the same time, causing an unavoidable mismatch period. Now it causes the least friction. * Devs couldn't readily test new in-dev variants without breaking/inconveniencing their own mobile experience. * Some users will have (potentially perpetually) outdated Anki clients and likely complain, wasting both dev & deck creator time. This way users always get to type and especially: The front side will always render as intended. --- rslib/src/template_filters.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/rslib/src/template_filters.rs b/rslib/src/template_filters.rs index 13d092134..f1aac788c 100644 --- a/rslib/src/template_filters.rs +++ b/rslib/src/template_filters.rs @@ -31,12 +31,12 @@ pub(crate) fn apply_filters<'a>( let mut text: Cow = text.into(); // type:cloze & type:nc are handled specially - let filters = if filters == ["cloze", "type"] { - &["type-cloze"] - } else if filters == ["nc", "type"] { - &["type-nc"] - } else { - filters + // other type: are passed as the default one + let filters = match filters { + ["cloze", "type"] => &["type-cloze"], + ["nc", "type"] => &["type-nc"], + [.., "type"] => &["type"], + _ => filters, }; for (idx, &filter_name) in filters.iter().enumerate() { @@ -259,6 +259,10 @@ field apply_filters("ignored", &["nc", "type"], "Text", &ctx), ("[[type:nc:Text]]".into(), vec![]) ); + assert_eq!( + apply_filters("ignored", &["some", "unknown", "type"], "Text", &ctx), + ("[[type:Text]]".into(), vec![]) + ); } #[test] From 5e6e19a7816388a5e36ea80a7b5914e970a33542 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 26 Oct 2024 20:02:53 +1000 Subject: [PATCH 040/113] Rust 1.82 --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 3c1f3ff7a..2c8c4172d 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] # older versions may fail to compile; newer versions may fail the clippy tests -channel = "1.81.0" +channel = "1.82.0" From 1bf10ded79d41cb7e072633535180589a72c5fe6 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 26 Oct 2024 20:03:04 +1000 Subject: [PATCH 041/113] Update translations --- ftl/core-repo | 2 +- ftl/qt-repo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ftl/core-repo b/ftl/core-repo index ee113ff14..8acffeda6 160000 --- a/ftl/core-repo +++ b/ftl/core-repo @@ -1 +1 @@ -Subproject commit ee113ff14cd5edc30bdfb1939ae237fdef5b0c2f +Subproject commit 8acffeda61b580d83693a13774d843459bf1d605 diff --git a/ftl/qt-repo b/ftl/qt-repo index 78c4b288d..6703424af 160000 --- a/ftl/qt-repo +++ b/ftl/qt-repo @@ -1 +1 @@ -Subproject commit 78c4b288dfc77988aece7442b2bca07dd94c9f69 +Subproject commit 6703424af002e5d18844a2fad74484bee16c9ccb From 1fb4430913e3d4032aefc07f52c8ed8bfad52f59 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 26 Oct 2024 20:13:24 +1000 Subject: [PATCH 042/113] Fix due date showing incorrectly in filtered deck Regressed in #3471 Closes #3515 --- rslib/src/stats/card.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rslib/src/stats/card.rs b/rslib/src/stats/card.rs index 1b2b1d376..97005e07f 100644 --- a/rslib/src/stats/card.rs +++ b/rslib/src/stats/card.rs @@ -94,7 +94,11 @@ impl Collection { Ok(match card.ctype { CardType::New => None, CardType::Review | CardType::Learn | CardType::Relearn => { - let due = card.due; + let due = if card.original_due != 0 { + card.original_due + } else { + card.due + }; if !is_unix_epoch_timestamp(due) { let days_remaining = due - (self.timing_today()?.days_elapsed as i32); let mut due_timestamp = TimestampSecs::now(); From 8d9251e7e57548a8041511b68727fb35a51d8cf8 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 26 Oct 2024 20:38:05 +1000 Subject: [PATCH 043/113] Remove FSRS client warning https://forums.ankiweb.net/t/anki-24-10-beta/49989/290 --- ftl/core/deck-config.ftl | 6 +++--- ts/routes/deck-options/FsrsOptionsOuter.svelte | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ftl/core/deck-config.ftl b/ftl/core/deck-config.ftl index 4a90216f4..ca34c4b1e 100644 --- a/ftl/core/deck-config.ftl +++ b/ftl/core/deck-config.ftl @@ -370,9 +370,6 @@ deck-config-historical-retention = Historical retention deck-config-smaller-is-better = Smaller numbers indicate a better fit to your review history. deck-config-steps-too-large-for-fsrs = When FSRS is enabled, steps of 1 day or more are not recommended. deck-config-get-params = Get Params -deck-config-fsrs-on-all-clients = - Please ensure all of your Anki clients are Anki(Mobile) 23.10+ or AnkiDroid 2.17+. FSRS will - not work correctly if one of your clients is older. deck-config-predicted-minimum-recommended-retention = Minimum recommended retention: { $num } deck-config-complete = { $num }% complete. deck-config-iterations = Iteration: { $count }... @@ -523,3 +520,6 @@ deck-config-compute-optimal-retention-tooltip3 = lead to a higher workload, because of the high forgetting rate. deck-config-seconds-to-show-question-tooltip-2 = When auto advance is activated, the number of seconds to wait before revealing the answer. Set to 0 to disable. deck-config-invalid-weights = Parameters must be either left blank to use the defaults, or must be 17 comma-separated numbers. +deck-config-fsrs-on-all-clients = + Please ensure all of your Anki clients are Anki(Mobile) 23.10+ or AnkiDroid 2.17+. FSRS will + not work correctly if one of your clients is older. diff --git a/ts/routes/deck-options/FsrsOptionsOuter.svelte b/ts/routes/deck-options/FsrsOptionsOuter.svelte index 1ade4d50d..f21d7ff3c 100644 --- a/ts/routes/deck-options/FsrsOptionsOuter.svelte +++ b/ts/routes/deck-options/FsrsOptionsOuter.svelte @@ -19,7 +19,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import FsrsOptions from "./FsrsOptions.svelte"; import GlobalLabel from "./GlobalLabel.svelte"; import type { DeckOptionsState } from "./lib"; - import Warning from "./Warning.svelte"; export let state: DeckOptionsState; export let api: Record; @@ -65,8 +64,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html modal.show(); carousel.to(index); } - - $: fsrsClientWarning = $fsrs ? tr.deckConfigFsrsOnAllClients() : ""; @@ -93,8 +90,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - - {#if $fsrs} Date: Sat, 26 Oct 2024 19:07:35 -0700 Subject: [PATCH 044/113] Enable strict_optional for aqt/overview.py --- .mypy.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mypy.ini b/.mypy.ini index 4a9cd17f4..30db8f069 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -44,6 +44,8 @@ strict_optional = True strict_optional = True [mypy-aqt.preferences] strict_optional = True +[mypy-aqt.overview] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] From 364a1ada00897a5aa6bf0f941b31387eca6f6182 Mon Sep 17 00:00:00 2001 From: bpnguyen107 <105088397+bpnguyen107@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:07:43 -0700 Subject: [PATCH 045/113] Fix mypy errors --- qt/aqt/overview.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qt/aqt/overview.py b/qt/aqt/overview.py index 20d276dbb..da017714f 100644 --- a/qt/aqt/overview.py +++ b/qt/aqt/overview.py @@ -224,13 +224,14 @@ class Overview: dyn = "" return f'
{desc}
' - def _table(self) -> str | None: + def _table(self) -> str: counts = list(self.mw.col.sched.counts()) current_did = self.mw.col.decks.get_current_id() deck_node = self.mw.col.sched.deck_due_tree(current_did) but = self.mw.button if self.mw.col.v3_scheduler(): + assert deck_node is not None buried_new = deck_node.new_count - counts[0] buried_learning = deck_node.learn_count - counts[1] buried_review = deck_node.review_count - counts[2] From 8189255b34fa574208b17ab6949c1e656d0ef407 Mon Sep 17 00:00:00 2001 From: bpnguyen107 <105088397+bpnguyen107@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:17:25 -0700 Subject: [PATCH 046/113] Enable strict_optional --- .mypy.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mypy.ini b/.mypy.ini index 4a9cd17f4..c13cdf5b4 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -44,6 +44,8 @@ strict_optional = True strict_optional = True [mypy-aqt.preferences] strict_optional = True +[mypy-aqt.customstudy] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] From c02f234ce0082dea6b60fede39ac06f5a514b416 Mon Sep 17 00:00:00 2001 From: bpnguyen107 <105088397+bpnguyen107@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:19:20 -0700 Subject: [PATCH 047/113] Fix mypy errors --- qt/aqt/customstudy.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qt/aqt/customstudy.py b/qt/aqt/customstudy.py index 730f3843b..eb8921627 100644 --- a/qt/aqt/customstudy.py +++ b/qt/aqt/customstudy.py @@ -144,7 +144,11 @@ class CustomStudy(QDialog): form.spin.setValue(current_spinner_value) form.preSpin.setText(text_before_spinner) form.postSpin.setText(text_after_spinner) - form.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(ok) + + ok_button = form.buttonBox.button(QDialogButtonBox.StandardButton.Ok) + assert ok_button is not None + ok_button.setText(ok) + self.radioIdx = idx def accept(self) -> None: From 98c62ab75f1490d995c541d523440ee867f650cb Mon Sep 17 00:00:00 2001 From: bpnguyen107 <105088397+bpnguyen107@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:27:00 -0700 Subject: [PATCH 048/113] Enable strict_optional --- .mypy.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mypy.ini b/.mypy.ini index 4a9cd17f4..67a2ca631 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -44,6 +44,8 @@ strict_optional = True strict_optional = True [mypy-aqt.preferences] strict_optional = True +[mypy-aqt.taglimit] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] From d7ed0fee16163b0e552ea1e1139dc05317509689 Mon Sep 17 00:00:00 2001 From: bpnguyen107 <105088397+bpnguyen107@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:33:04 -0700 Subject: [PATCH 049/113] Fix mypy errors --- qt/aqt/taglimit.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/qt/aqt/taglimit.py b/qt/aqt/taglimit.py index 4132deafa..3893ed0d6 100644 --- a/qt/aqt/taglimit.py +++ b/qt/aqt/taglimit.py @@ -50,7 +50,9 @@ class TagLimit(QDialog): list.addItem(item) if select: idx = list.indexFromItem(item) - list.selectionModel().select( + list_selection_model = list.selectionModel() + assert list_selection_model is not None + list_selection_model.select( idx, QItemSelectionModel.SelectionFlag.Select ) @@ -77,12 +79,16 @@ class TagLimit(QDialog): if want_active: item = self.form.activeList.item(c) idx = self.form.activeList.indexFromItem(item) - if self.form.activeList.selectionModel().isSelected(idx): + active_list_selection_model = self.form.activeList.selectionModel() + assert active_list_selection_model is not None + if active_list_selection_model.isSelected(idx): include_tags.append(tag.name) # inactive item = self.form.inactiveList.item(c) idx = self.form.inactiveList.indexFromItem(item) - if self.form.inactiveList.selectionModel().isSelected(idx): + inactive_list_selection_model = self.form.inactiveList.selectionModel() + assert inactive_list_selection_model is not None + if inactive_list_selection_model.isSelected(idx): exclude_tags.append(tag.name) if (len(include_tags) + len(exclude_tags)) > 100: From 0ce907fe5b2310cdb150f0ff44bd245633ec6038 Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Mon, 28 Oct 2024 12:10:10 +0800 Subject: [PATCH 050/113] Fix/buried new cards shouldn't be counted in daily load (#3530) * Fix/buried new cards shouldn't be counted in daily load * exclude new cards by its type * ./ninja format --- rslib/src/stats/graphs/future_due.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rslib/src/stats/graphs/future_due.rs b/rslib/src/stats/graphs/future_due.rs index 3c0194a38..a98f2de5c 100644 --- a/rslib/src/stats/graphs/future_due.rs +++ b/rslib/src/stats/graphs/future_due.rs @@ -7,6 +7,7 @@ use anki_proto::stats::graphs_response::FutureDue; use super::GraphsContext; use crate::card::CardQueue; +use crate::card::CardType; use crate::scheduler::timing::is_unix_epoch_timestamp; impl GraphsContext { @@ -26,7 +27,9 @@ impl GraphsContext { due - (self.days_elapsed as i32) }; - daily_load += 1.0 / c.interval.max(1) as f32; + if c.ctype != CardType::New { + daily_load += 1.0 / c.interval.max(1) as f32; + } // still want to filtered out buried cards that are due today if due_day == 0 && matches!(c.queue, CardQueue::UserBuried | CardQueue::SchedBuried) { From 28892996704478a8a2bf0c22c63ba17542e18963 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Sun, 27 Oct 2024 21:16:42 -0700 Subject: [PATCH 051/113] Enable strict_optional for aqt/deckbrowser.py (#3537) * Enable strict_optional * Fix mypy errors --- .mypy.ini | 2 ++ qt/aqt/deckbrowser.py | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index 891aaa659..c0d7700dc 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -50,6 +50,8 @@ strict_optional = True strict_optional = True [mypy-aqt.taglimit] strict_optional = True +[mypy-aqt.deckbrowser] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py index a9e450871..a3969cedf 100644 --- a/qt/aqt/deckbrowser.py +++ b/qt/aqt/deckbrowser.py @@ -309,12 +309,16 @@ class DeckBrowser: def _showOptions(self, did: str) -> None: m = QMenu(self.mw) a = m.addAction(tr.actions_rename()) + assert a is not None qconnect(a.triggered, lambda b, did=did: self._rename(DeckId(int(did)))) a = m.addAction(tr.actions_options()) + assert a is not None qconnect(a.triggered, lambda b, did=did: self._options(DeckId(int(did)))) a = m.addAction(tr.actions_export()) + assert a is not None qconnect(a.triggered, lambda b, did=did: self._export(DeckId(int(did)))) a = m.addAction(tr.actions_delete()) + assert a is not None qconnect(a.triggered, lambda b, did=did: self._delete(DeckId(int(did)))) gui_hooks.deck_browser_will_show_options_menu(m, int(did)) m.popup(QCursor.pos()) @@ -357,9 +361,9 @@ class DeckBrowser: ).run_in_background() def _delete(self, did: DeckId) -> None: - deck_name = self.mw.col.decks.find_deck_in_tree( - self._render_data.tree, did - ).name + deck = self.mw.col.decks.find_deck_in_tree(self._render_data.tree, did) + assert deck is not None + deck_name = deck.name remove_decks( parent=self.mw, deck_ids=[did], deck_name=deck_name ).run_in_background() From fbd53726ccf3ea8d4011e65487679364763559d8 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Sun, 27 Oct 2024 21:18:16 -0700 Subject: [PATCH 052/113] Enable strict_optional for aqt/deckdescription.py (#3538) * Enable strict_optional * Fix mypy errors --- .mypy.ini | 2 ++ qt/aqt/deckdescription.py | 1 + 2 files changed, 3 insertions(+) diff --git a/.mypy.ini b/.mypy.ini index c0d7700dc..bc5670dbe 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -50,6 +50,8 @@ strict_optional = True strict_optional = True [mypy-aqt.taglimit] strict_optional = True +[mypy-aqt.deckdescription] +strict_optional = True [mypy-aqt.deckbrowser] strict_optional = True [mypy-anki.scheduler.base] diff --git a/qt/aqt/deckdescription.py b/qt/aqt/deckdescription.py index 01b41eaaf..261f52ea2 100644 --- a/qt/aqt/deckdescription.py +++ b/qt/aqt/deckdescription.py @@ -60,6 +60,7 @@ class DeckDescriptionDialog(QDialog): button_box = QDialogButtonBox() ok = button_box.addButton(QDialogButtonBox.StandardButton.Ok) + assert ok is not None qconnect(ok.clicked, self.save_and_accept) box.addWidget(button_box) From 7f58ca213c66d3bdc8edb1180c31f1182985521b Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Sun, 27 Oct 2024 21:19:31 -0700 Subject: [PATCH 053/113] Enable strict_optional for aqt/modelchooser.py (#3539) * Enable strict_optional * Fix mypy errors --- .mypy.ini | 2 ++ qt/aqt/modelchooser.py | 1 + 2 files changed, 3 insertions(+) diff --git a/.mypy.ini b/.mypy.ini index bc5670dbe..818bcfb26 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -50,6 +50,8 @@ strict_optional = True strict_optional = True [mypy-aqt.taglimit] strict_optional = True +[mypy-aqt.modelchooser] +strict_optional = True [mypy-aqt.deckdescription] strict_optional = True [mypy-aqt.deckbrowser] diff --git a/qt/aqt/modelchooser.py b/qt/aqt/modelchooser.py index cdc75cd06..15c5347e4 100644 --- a/qt/aqt/modelchooser.py +++ b/qt/aqt/modelchooser.py @@ -84,6 +84,7 @@ class ModelChooser(QHBoxLayout): if not ret.name: return m = self.deck.models.by_name(ret.name) + assert m is not None self.deck.conf["curModel"] = m["id"] cdeck = self.deck.decks.current() cdeck["mid"] = m["id"] From a25edecc884433f991e7bea02e97614a5a97f75a Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Tue, 29 Oct 2024 02:05:54 -0700 Subject: [PATCH 054/113] Enable strict_optional for aqt/studydeck, tts, mediasrv (#3542) * Enable strict_optional for studydeck * Fix mypy errors * Enable strict_optional for tts * Fix mypy errors in tts * Enable strict_optional for mediasrv * Fix mypy errors in mediasrv --- .mypy.ini | 6 ++++++ qt/aqt/mediasrv.py | 8 ++++++-- qt/aqt/studydeck.py | 3 ++- qt/aqt/tts.py | 2 ++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index 818bcfb26..96483e1cc 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -56,6 +56,12 @@ strict_optional = True strict_optional = True [mypy-aqt.deckbrowser] strict_optional = True +[mypy-aqt.studydeck] +strict_optional = True +[mypy-aqt.tts] +strict_optional = True +[mypy-aqt.mediasrv] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/mediasrv.py b/qt/aqt/mediasrv.py index ca4f23503..15d9a0fd1 100644 --- a/qt/aqt/mediasrv.py +++ b/qt/aqt/mediasrv.py @@ -735,8 +735,12 @@ def _extract_page_context() -> PageContext: return PageContext.NON_LEGACY_PAGE elif referer.path == "/_anki/legacyPageData": query_params = parse_qs(referer.query) - id = int(query_params.get("id", [None])[0]) - return aqt.mw.mediaServer.get_page_context(id) + query_id = query_params.get("id") + if not query_id: + return PageContext.UNKNOWN + id = int(query_id[0]) + page_context = aqt.mw.mediaServer.get_page_context(id) + return page_context if page_context else PageContext.UNKNOWN else: return PageContext.UNKNOWN diff --git a/qt/aqt/studydeck.py b/qt/aqt/studydeck.py index 537c7d151..d1c0a5c47 100644 --- a/qt/aqt/studydeck.py +++ b/qt/aqt/studydeck.py @@ -101,7 +101,7 @@ class StudyDeck(QDialog): else: self.exec() - def eventFilter(self, obj: QObject, evt: QEvent) -> bool: + def eventFilter(self, obj: QObject | None, evt: QEvent | None) -> bool: if isinstance(evt, QKeyEvent) and evt.type() == QEvent.Type.KeyPress: new_row = current_row = self.form.list.currentRow() rows_count = self.form.list.count() @@ -178,6 +178,7 @@ class StudyDeck(QDialog): def success(out: OpChangesWithId) -> None: deck = self.mw.col.decks.get(DeckId(out.id)) + assert deck is not None self.name = deck["name"] self.accept_with_callback() diff --git a/qt/aqt/tts.py b/qt/aqt/tts.py index cd2884795..3cd0e5ddf 100644 --- a/qt/aqt/tts.py +++ b/qt/aqt/tts.py @@ -189,6 +189,7 @@ class MacTTSPlayer(TTSProcessPlayer): stderr=subprocess.DEVNULL, ) # write the input text to stdin + assert self._process.stdin is not None self._process.stdin.write(tag.field_text.encode("utf8")) self._process.stdin.close() self._wait_for_termination(tag) @@ -247,6 +248,7 @@ class MacTTSFilePlayer(MacTTSPlayer): stderr=subprocess.DEVNULL, ) # write the input text to stdin + assert self._process.stdin is not None self._process.stdin.write(tag.field_text.encode("utf8")) self._process.stdin.close() self._wait_for_termination(tag) From 8b84583433d6400e64359dccfe1e2edde3df3e34 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Wed, 30 Oct 2024 03:40:40 -0700 Subject: [PATCH 055/113] Enable strict_optional for aqt/clayout, changenotetype, fields (#3544) * Enable strict_optional for clayout * Fix mypy errors * Enable strict_optional for changenotetype * Fix mypy errors * Enable strict_optional for fields * Fix mypy errors --- .mypy.ini | 6 ++++++ qt/aqt/changenotetype.py | 2 +- qt/aqt/clayout.py | 26 ++++++++++++++++++++------ qt/aqt/fields.py | 24 +++++++++++++++++------- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index 96483e1cc..524a62168 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -62,6 +62,12 @@ strict_optional = True strict_optional = True [mypy-aqt.mediasrv] strict_optional = True +[mypy-aqt.changenotetype] +strict_optional = True +[mypy-aqt.clayout] +strict_optional = True +[mypy-aqt.fields] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/changenotetype.py b/qt/aqt/changenotetype.py index 0484c2ff8..3ab9a87e8 100644 --- a/qt/aqt/changenotetype.py +++ b/qt/aqt/changenotetype.py @@ -63,7 +63,7 @@ class ChangeNotetypeDialog(QDialog): def reject(self) -> None: self.web.cleanup() - self.web = None + self.web = None # type: ignore saveGeom(self, self.TITLE) QDialog.reject(self) diff --git a/qt/aqt/clayout.py b/qt/aqt/clayout.py index bdd7f02d3..8f467e379 100644 --- a/qt/aqt/clayout.py +++ b/qt/aqt/clayout.py @@ -61,7 +61,9 @@ class CardLayout(QDialog): self.ord = ord self.col = self.mw.col.weakref() self.mm = self.mw.col.models - self.model = note.note_type() + note_type = note.note_type() + assert note_type is not None + self.model = note_type self.templates = self.model["tmpls"] self.fill_empty_action_toggled = fill_empty self.night_mode_is_enabled = theme_manager.night_mode @@ -404,6 +406,7 @@ class CardLayout(QDialog): m = QMenu(self) a = m.addAction(tr.card_templates_fill_empty()) + assert a is not None a.setCheckable(True) a.setChecked(self.fill_empty_action_toggled) qconnect(a.triggered, self.on_fill_empty_action_toggled) @@ -411,11 +414,13 @@ class CardLayout(QDialog): a.setVisible(False) a = m.addAction(tr.card_templates_night_mode()) + assert a is not None a.setCheckable(True) a.setChecked(self.night_mode_is_enabled) qconnect(a.triggered, self.on_night_mode_action_toggled) a = m.addAction(tr.card_templates_add_mobile_class()) + assert a is not None a.setCheckable(True) a.setChecked(self.mobile_emulation_enabled) qconnect(a.toggled, self.on_mobile_class_action_toggled) @@ -754,6 +759,7 @@ class CardLayout(QDialog): a = m.addAction( tr.actions_with_ellipsis(action=tr.card_templates_restore_to_default()) ) + assert a is not None qconnect( a.triggered, lambda: self.on_restore_to_default(), # pylint: disable=unnecessary-lambda @@ -761,15 +767,19 @@ class CardLayout(QDialog): if not self._isCloze(): a = m.addAction(tr.card_templates_add_card_type()) + assert a is not None qconnect(a.triggered, self.onAddCard) a = m.addAction(tr.card_templates_remove_card_type()) + assert a is not None qconnect(a.triggered, self.onRemove) a = m.addAction(tr.card_templates_rename_card_type()) + assert a is not None qconnect(a.triggered, self.onRename) a = m.addAction(tr.card_templates_reposition_card_type()) + assert a is not None qconnect(a.triggered, self.onReorder) m.addSeparator() @@ -780,9 +790,11 @@ class CardLayout(QDialog): else: s = tr.card_templates_off() a = m.addAction(tr.card_templates_deck_override() + s) + assert a is not None qconnect(a.triggered, self.onTargetDeck) a = m.addAction(tr.card_templates_browser_appearance()) + assert a is not None qconnect(a.triggered, self.onBrowserDisplay) m.popup(self.topAreaForm.templateOptions.mapToGlobal(QPoint(0, 0))) @@ -834,7 +846,9 @@ class CardLayout(QDialog): te.setCol(self.col) l.addWidget(te) if t["did"]: - te.setText(self.col.decks.get(t["did"])["name"]) + deck = self.col.decks.get(t["did"]) + assert deck is not None + te.setText(deck["name"]) te.selectAll() bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) qconnect(bb.rejected, d.close) @@ -927,10 +941,10 @@ class CardLayout(QDialog): saveGeom(self, "CardLayout") saveSplitter(self.mainArea, "CardLayoutMainArea") self.preview_web.cleanup() - self.preview_web = None - self.model = None - self.rendered_card = None - self.mw = None + self.preview_web = None # type: ignore + self.model = None # type: ignore + self.rendered_card = None # type: ignore + self.mw = None # type: ignore def onHelp(self) -> None: openHelp(HelpPage.TEMPLATES) diff --git a/qt/aqt/fields.py b/qt/aqt/fields.py index da81c9ff7..0a570239e 100644 --- a/qt/aqt/fields.py +++ b/qt/aqt/fields.py @@ -51,15 +51,20 @@ class FieldDialog(QDialog): self.webview = None disable_help_button(self) - self.form.buttonBox.button(QDialogButtonBox.StandardButton.Help).setAutoDefault( - False - ) - self.form.buttonBox.button( + help_button = self.form.buttonBox.button(QDialogButtonBox.StandardButton.Help) + assert help_button is not None + help_button.setAutoDefault(False) + + cancel_button = self.form.buttonBox.button( QDialogButtonBox.StandardButton.Cancel - ).setAutoDefault(False) - self.form.buttonBox.button(QDialogButtonBox.StandardButton.Save).setAutoDefault( - False ) + assert cancel_button is not None + cancel_button.setAutoDefault(False) + + save_button = self.form.buttonBox.button(QDialogButtonBox.StandardButton.Save) + assert save_button is not None + save_button.setAutoDefault(False) + self.currentIdx: int | None = None self.fillFields() self.setupSignals() @@ -112,6 +117,7 @@ class FieldDialog(QDialog): # for pylint return # the item in idx is removed thus subtract 1. + assert idx is not None if idx < dropPos: movePos -= 1 self.moveField(movePos + 1) # convert to 1 based. @@ -144,6 +150,9 @@ class FieldDialog(QDialog): return txt def onRename(self) -> None: + if self.currentIdx is None: + return + idx = self.currentIdx f = self.model["flds"][idx] name = self._uniqueName(tr.actions_new_name(), self.currentIdx, f["name"]) @@ -195,6 +204,7 @@ class FieldDialog(QDialog): def onPosition(self, delta: int = -1) -> None: idx = self.currentIdx + assert idx is not None l = len(self.model["flds"]) txt = getOnlyText(tr.fields_new_position_1(val=l), default=str(idx + 1)) if not txt: From 0fa9e0ef5133fd631b2207d6796143f5657aee8e Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Tue, 5 Nov 2024 16:20:28 +0800 Subject: [PATCH 056/113] Feat/align FSRS-rs with PyTorch Implementation (#3540) * Feat/align FSRS-rs with PyTorch Implementation * Update to FSRS-rs v1.4.2 fix https://forums.ankiweb.net/t/anki-24-10-release-candidate/51191/37?u=l.m.sherlock * Update to FSRS-rs v1.4.3 improve performance: https://github.com/open-spaced-repetition/fsrs-rs/pull/252 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- cargo/licenses.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2393ff6f8..a454168b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1860,9 +1860,9 @@ dependencies = [ [[package]] name = "fsrs" -version = "1.3.5" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42155527199b3e7b6ad47e9db849ee25bd5bd436ee17a72ae0a3de646a20021a" +checksum = "de570dbbc7b95c5cf5f77c905b3b54b16352c1b48694e6761d716fb92b8db67c" dependencies = [ "burn", "itertools 0.12.1", diff --git a/Cargo.toml b/Cargo.toml index c3d6241f1..da39632a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ git = "https://github.com/ankitects/linkcheck.git" rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca" [workspace.dependencies.fsrs] -version = "=1.3.5" +version = "=1.4.3" # git = "https://github.com/open-spaced-repetition/fsrs-rs.git" # rev = "58ca25ed2bc4bb1dc376208bbcaed7f5a501b941" # path = "../open-spaced-repetition/fsrs-rs" diff --git a/cargo/licenses.json b/cargo/licenses.json index cbbede5ca..ea1743568 100644 --- a/cargo/licenses.json +++ b/cargo/licenses.json @@ -1225,7 +1225,7 @@ }, { "name": "fsrs", - "version": "1.3.5", + "version": "1.4.3", "authors": "Open Spaced Repetition", "repository": "https://github.com/open-spaced-repetition/fsrs-rs", "license": "BSD-3-Clause", From 7629a1b76fe4ed2a5efebc8456cfce8c7f814815 Mon Sep 17 00:00:00 2001 From: Abdo Date: Tue, 5 Nov 2024 11:23:50 +0300 Subject: [PATCH 057/113] Fix flaky tests (#3541) * Fix flaky state_application() test * Try to fix flaky unicode_normalization() test --- rslib/io/src/lib.rs | 16 +++++++++ rslib/src/media/check.rs | 3 +- rslib/src/scheduler/answering/mod.rs | 49 ++++++++++++---------------- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/rslib/io/src/lib.rs b/rslib/io/src/lib.rs index 100d397d3..c1d4c0205 100644 --- a/rslib/io/src/lib.rs +++ b/rslib/io/src/lib.rs @@ -8,6 +8,7 @@ use std::fs::FileTimes; use std::fs::OpenOptions; use std::io::Read; use std::io::Seek; +use std::io::Write; use std::path::Component; use std::path::Path; use std::path::PathBuf; @@ -54,6 +55,21 @@ pub fn write_file(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result< }) } +pub fn write_file_and_flush( + path: impl AsRef + Clone, + contents: impl AsRef<[u8]>, +) -> Result<()> { + let mut file = create_file(path.clone())?; + file.write_all(contents.as_ref()).context(FileIoSnafu { + path: path.clone().as_ref(), + op: FileOp::Write, + })?; + file.sync_all().context(FileIoSnafu { + path: path.as_ref(), + op: FileOp::Sync, + }) +} + /// See [File::set_times]. pub fn set_file_times(path: impl AsRef, times: FileTimes) -> Result<()> { #[cfg(not(windows))] diff --git a/rslib/src/media/check.rs b/rslib/src/media/check.rs index c87fadb91..bc85b177b 100644 --- a/rslib/src/media/check.rs +++ b/rslib/src/media/check.rs @@ -546,6 +546,7 @@ pub(crate) mod test { use anki_io::create_dir; use anki_io::read_to_string; use anki_io::write_file; + use anki_io::write_file_and_flush; use tempfile::tempdir; use tempfile::TempDir; @@ -696,7 +697,7 @@ Unused: unused.jpg fn unicode_normalization() -> Result<()> { let (_dir, mgr, mut col) = common_setup()?; - write_file(mgr.media_folder.join("ぱぱ.jpg"), "nfd encoding")?; + write_file_and_flush(mgr.media_folder.join("ぱぱ.jpg"), "nfd encoding")?; let mut output = { let mut checker = col.media_checker()?; diff --git a/rslib/src/scheduler/answering/mod.rs b/rslib/src/scheduler/answering/mod.rs index 61ff13fbb..2d3c34a28 100644 --- a/rslib/src/scheduler/answering/mod.rs +++ b/rslib/src/scheduler/answering/mod.rs @@ -644,10 +644,9 @@ mod test { // new->learning let post_answer = col.answer_again(); - assert_eq!( - post_answer.new_state, - current_state(&mut col, post_answer.card_id) - ); + let mut current = current_state(&mut col, post_answer.card_id); + col.set_elapsed_secs_equal(&post_answer.new_state, &mut current); + assert_eq!(post_answer.new_state, current); let card = col.storage.get_card(post_answer.card_id)?.unwrap(); assert_eq!(card.queue, CardQueue::Learn); assert_eq!(card.remaining_steps, 2); @@ -656,10 +655,9 @@ mod test { col.storage.db.execute_batch("update cards set due=0")?; col.clear_study_queues(); let post_answer = col.answer_good(); - assert_eq!( - post_answer.new_state, - current_state(&mut col, post_answer.card_id) - ); + let mut current = current_state(&mut col, post_answer.card_id); + col.set_elapsed_secs_equal(&post_answer.new_state, &mut current); + assert_eq!(post_answer.new_state, current); let card = col.storage.get_card(post_answer.card_id)?.unwrap(); assert_eq!(card.queue, CardQueue::Learn); assert_eq!(card.remaining_steps, 1); @@ -672,10 +670,9 @@ mod test { if let CardState::Normal(NormalState::Review(state)) = &mut post_answer.new_state { state.elapsed_days = 1; }; - assert_eq!( - post_answer.new_state, - current_state(&mut col, post_answer.card_id) - ); + let mut current = current_state(&mut col, post_answer.card_id); + col.set_elapsed_secs_equal(&post_answer.new_state, &mut current); + assert_eq!(post_answer.new_state, current); let card = col.storage.get_card(post_answer.card_id)?.unwrap(); assert_eq!(card.queue, CardQueue::Review); assert_eq!(card.interval, 1); @@ -688,10 +685,9 @@ mod test { if let CardState::Normal(NormalState::Review(state)) = &mut post_answer.new_state { state.elapsed_days = 4; }; - assert_eq!( - post_answer.new_state, - current_state(&mut col, post_answer.card_id) - ); + let mut current = current_state(&mut col, post_answer.card_id); + col.set_elapsed_secs_equal(&post_answer.new_state, &mut current); + assert_eq!(post_answer.new_state, current); let card = col.storage.get_card(post_answer.card_id)?.unwrap(); assert_eq!(card.queue, CardQueue::Review); assert_eq!(card.interval, 4); @@ -704,10 +700,9 @@ mod test { if let CardState::Normal(NormalState::Relearning(state)) = &mut post_answer.new_state { state.review.elapsed_days = 1; }; - assert_eq!( - post_answer.new_state, - current_state(&mut col, post_answer.card_id) - ); + let mut current = current_state(&mut col, post_answer.card_id); + col.set_elapsed_secs_equal(&post_answer.new_state, &mut current); + assert_eq!(post_answer.new_state, current); let card = col.storage.get_card(post_answer.card_id)?.unwrap(); assert_eq!(card.queue, CardQueue::Learn); assert_eq!(card.ctype, CardType::Relearn); @@ -722,10 +717,9 @@ mod test { if let CardState::Normal(NormalState::Relearning(state)) = &mut post_answer.new_state { state.review.elapsed_days = 1; }; - assert_eq!( - post_answer.new_state, - current_state(&mut col, post_answer.card_id) - ); + let mut current = current_state(&mut col, post_answer.card_id); + col.set_elapsed_secs_equal(&post_answer.new_state, &mut current); + assert_eq!(post_answer.new_state, current); let card = col.storage.get_card(post_answer.card_id)?.unwrap(); assert_eq!(card.queue, CardQueue::Learn); assert_eq!(card.lapses, 1); @@ -737,10 +731,9 @@ mod test { if let CardState::Normal(NormalState::Review(state)) = &mut post_answer.new_state { state.elapsed_days = 1; }; - assert_eq!( - post_answer.new_state, - current_state(&mut col, post_answer.card_id) - ); + let mut current = current_state(&mut col, post_answer.card_id); + col.set_elapsed_secs_equal(&post_answer.new_state, &mut current); + assert_eq!(post_answer.new_state, current); let card = col.storage.get_card(post_answer.card_id)?.unwrap(); assert_eq!(card.queue, CardQueue::Review); assert_eq!(card.interval, 1); From 43d9b00b853c7ce79e5d644a68f4815bd655dd00 Mon Sep 17 00:00:00 2001 From: Abdo Date: Tue, 5 Nov 2024 11:25:06 +0300 Subject: [PATCH 058/113] Remove legacy import option (#3536) * Remove legacy import option * Always return False in legacy_import_export() --- qt/aqt/forms/preferences.ui | 23 ----------------------- qt/aqt/preferences.py | 3 --- qt/aqt/profiles.py | 3 ++- 3 files changed, 2 insertions(+), 27 deletions(-) diff --git a/qt/aqt/forms/preferences.ui b/qt/aqt/forms/preferences.ui index 58db104c7..34de8c80e 100644 --- a/qt/aqt/forms/preferences.ui +++ b/qt/aqt/forms/preferences.ui @@ -611,28 +611,6 @@ - - - - preferences_import_export - - - - - - - 0 - 0 - - - - Legacy import/export handling - - - - - - @@ -1293,7 +1271,6 @@ useCurrent default_search_text ignore_accents_in_search - legacy_import_export syncMedia syncOnProgramOpen autoSyncMedia diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py index aef3dc818..7befe4ca2 100644 --- a/qt/aqt/preferences.py +++ b/qt/aqt/preferences.py @@ -359,7 +359,6 @@ class Preferences(QDialog): ) self.form.styleLabel.setVisible(not is_win) self.form.styleComboBox.setVisible(not is_win) - self.form.legacy_import_export.setChecked(self.mw.pm.legacy_import_export()) qconnect(self.form.resetWindowSizes.clicked, self.on_reset_window_sizes) self.setup_language() @@ -377,8 +376,6 @@ class Preferences(QDialog): self.mw.pm.setUiScale(newScale) restart_required = True - self.mw.pm.set_legacy_import_export(self.form.legacy_import_export.isChecked()) - if restart_required: showInfo(tr.preferences_changes_will_take_effect_when_you()) diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py index 469908c1b..817e00139 100644 --- a/qt/aqt/profiles.py +++ b/qt/aqt/profiles.py @@ -636,7 +636,8 @@ create table if not exists profiles self.meta[f"{self.editor_key(mode)}TagsCollapsed"] = collapsed def legacy_import_export(self) -> bool: - return self.meta.get("legacy_import", False) + "Always returns False so users with this option enabled are not stuck on the legacy importer after the UI option is removed." + return False def set_legacy_import_export(self, enabled: bool) -> None: self.meta["legacy_import"] = enabled From 9986ee54fdd58449b4e798ef7477d53343456cfe Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 5 Nov 2024 18:30:08 +1000 Subject: [PATCH 059/113] Latest waitress CVE --- python/requirements.bundle.txt | 6 +++--- python/requirements.dev.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/requirements.bundle.txt b/python/requirements.bundle.txt index a781dd431..a50f9c50d 100644 --- a/python/requirements.bundle.txt +++ b/python/requirements.bundle.txt @@ -386,9 +386,9 @@ urllib3==2.2.2 \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 # via requests -waitress==3.0.0 \ - --hash=sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1 \ - --hash=sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669 +waitress==3.0.1 \ + --hash=sha256:26cdbc593093a15119351690752c99adc13cbc6786d75f7b6341d1234a3730ac \ + --hash=sha256:ef0c1f020d9f12a515c4ec65c07920a702613afcad1dbfdc3bcec256b6c072b3 # via -r requirements.aqt.in werkzeug==3.0.6 \ --hash=sha256:1bc0c2310d2fbb07b1dd1105eba2f7af72f322e1e455f2f93c993bee8c8a5f17 \ diff --git a/python/requirements.dev.txt b/python/requirements.dev.txt index 27433ebf6..ea6a57f3b 100644 --- a/python/requirements.dev.txt +++ b/python/requirements.dev.txt @@ -608,9 +608,9 @@ urllib3==2.2.2 \ # via # requests # types-requests -waitress==3.0.0 \ - --hash=sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1 \ - --hash=sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669 +waitress==3.0.1 \ + --hash=sha256:26cdbc593093a15119351690752c99adc13cbc6786d75f7b6341d1234a3730ac \ + --hash=sha256:ef0c1f020d9f12a515c4ec65c07920a702613afcad1dbfdc3bcec256b6c072b3 # via -r requirements.aqt.in websocket-client==1.8.0 \ --hash=sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526 \ From 898c91284bc97c928adbf1bcc8ca885b068dac5f Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 5 Nov 2024 18:30:29 +1000 Subject: [PATCH 060/113] Update translations --- ftl/core-repo | 2 +- ftl/qt-repo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ftl/core-repo b/ftl/core-repo index 8acffeda6..05e08f99c 160000 --- a/ftl/core-repo +++ b/ftl/core-repo @@ -1 +1 @@ -Subproject commit 8acffeda61b580d83693a13774d843459bf1d605 +Subproject commit 05e08f99cd97b9cf5d7c0cfd653ad98c53a7715a diff --git a/ftl/qt-repo b/ftl/qt-repo index 6703424af..b265e151a 160000 --- a/ftl/qt-repo +++ b/ftl/qt-repo @@ -1 +1 @@ -Subproject commit 6703424af002e5d18844a2fad74484bee16c9ccb +Subproject commit b265e151a8f9a77dbb061257d32739c5db2a4be2 From 442ddb085a7e0ad53ebfe0dd36317007accf9c59 Mon Sep 17 00:00:00 2001 From: Abdo Date: Tue, 5 Nov 2024 17:49:48 +0300 Subject: [PATCH 061/113] Fix UI hanging with empty context menu (#3553) --- qt/aqt/webview.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index 50c4fdfe7..065d5956e 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -381,7 +381,8 @@ class AnkiWebView(QWebEngineView): m = QMenu(self) self._maybe_add_copy_action(m) gui_hooks.webview_will_show_context_menu(self, m) - m.popup(QCursor.pos()) + if m.actions(): + m.popup(QCursor.pos()) def _maybe_add_copy_action(self, menu: QMenu) -> None: if self.hasSelection(): From 4dcbcdb0ce0c070af5101585d8004d319a349361 Mon Sep 17 00:00:00 2001 From: Abdo Date: Thu, 7 Nov 2024 01:32:00 +0300 Subject: [PATCH 062/113] Escape special search characters in preset name (#3554) --- ts/routes/deck-options/FsrsOptions.svelte | 8 ++++---- ts/routes/deck-options/lib.ts | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ts/routes/deck-options/FsrsOptions.svelte b/ts/routes/deck-options/FsrsOptions.svelte index 28401169c..6a3501ea4 100644 --- a/ts/routes/deck-options/FsrsOptions.svelte +++ b/ts/routes/deck-options/FsrsOptions.svelte @@ -64,7 +64,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html optimalRetention = 0; } $: computing = computingParams || checkingParams || computingRetention; - $: defaultparamSearch = `preset:"${state.getCurrentName()}" -is:suspended`; + $: defaultparamSearch = `preset:"${state.getCurrentNameForSearch()}" -is:suspended`; $: roundedRetention = Number($config.desiredRetention.toFixed(2)); $: desiredRetentionWarning = getRetentionWarning(roundedRetention); $: retentionWarningClass = getRetentionWarningClass(roundedRetention); @@ -92,7 +92,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html newLimit: $config.newPerDay, reviewLimit: $config.reviewsPerDay, maxInterval: $config.maximumReviewInterval, - search: `preset:"${state.getCurrentName()}" -is:suspended`, + search: `preset:"${state.getCurrentNameForSearch()}" -is:suspended`, }); function getRetentionWarning(retention: number): string { @@ -236,7 +236,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html async () => { optimalRetentionRequest.maxInterval = $config.maximumReviewInterval; optimalRetentionRequest.params = fsrsParams($config); - optimalRetentionRequest.search = `preset:"${state.getCurrentName()}" -is:suspended`; + optimalRetentionRequest.search = `preset:"${state.getCurrentNameForSearch()}" -is:suspended`; const resp = await computeOptimalRetention(optimalRetentionRequest); optimalRetention = resp.optimalRetention; computeRetentionProgress = undefined; @@ -322,7 +322,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html async () => { simulateFsrsRequest.params = fsrsParams($config); simulateFsrsRequest.desiredRetention = $config.desiredRetention; - simulateFsrsRequest.search = `preset:"${state.getCurrentName()}" -is:suspended`; + simulateFsrsRequest.search = `preset:"${state.getCurrentNameForSearch()}" -is:suspended`; simulateProgressString = "processing..."; resp = await simulateFsrsReview(simulateFsrsRequest); }, diff --git a/ts/routes/deck-options/lib.ts b/ts/routes/deck-options/lib.ts index dce872bd9..549157757 100644 --- a/ts/routes/deck-options/lib.ts +++ b/ts/routes/deck-options/lib.ts @@ -139,6 +139,10 @@ export class DeckOptionsState { return this.configs[this.selectedIdx].config.name; } + getCurrentNameForSearch(): string { + return this.getCurrentName().replace(/([\\"])/g, "\\$1"); + } + setCurrentName(name: string): void { if (this.configs[this.selectedIdx].config.name === name) { return; From 11d2b91268dafd27f985beea48d72d4eb61a9e7c Mon Sep 17 00:00:00 2001 From: Abdo Date: Thu, 7 Nov 2024 01:32:42 +0300 Subject: [PATCH 063/113] Fix target deck reset to notetype-specific setting (#3555) --- qt/aqt/addcards.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py index f99829fd0..a447b95c1 100644 --- a/qt/aqt/addcards.py +++ b/qt/aqt/addcards.py @@ -152,10 +152,13 @@ class AddCards(QMainWindow): def on_deck_changed(self, deck_id: int) -> None: gui_hooks.add_cards_did_change_deck(deck_id) - def on_notetype_change(self, notetype_id: NotetypeId) -> None: + def on_notetype_change( + self, notetype_id: NotetypeId, update_deck: bool = True + ) -> None: # need to adjust current deck? - if deck_id := self.col.default_deck_for_notetype(notetype_id): - self.deck_chooser.selected_deck_id = deck_id + if update_deck: + if deck_id := self.col.default_deck_for_notetype(notetype_id): + self.deck_chooser.selected_deck_id = deck_id # only used for detecting changed sticky fields on close self._last_added_note = None @@ -224,7 +227,8 @@ class AddCards(QMainWindow): self.col.defaults_for_adding( current_review_card=self.mw.reviewer.card ).notetype_id - ) + ), + update_deck=False, ) def _new_note(self) -> Note: From ac731624e18ae6679f315298d8dfbc51d885f904 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:33:41 -0800 Subject: [PATCH 064/113] Enable strict_optional for aqt/deckoptions, editcurrent, filtered_deck (#3556) * Enable strict_optional for filtered_deck * Fix mypy errors * Enable strict_optional for editcurrent * Fix mypy errors * Enable strict_optional for deckoptions * Fix mypy errors --- .mypy.ini | 6 ++++++ qt/aqt/deckoptions.py | 18 +++++++++++++----- qt/aqt/editcurrent.py | 5 ++++- qt/aqt/filtered_deck.py | 7 ++++--- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index 524a62168..93ed0aaad 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -68,6 +68,12 @@ strict_optional = True strict_optional = True [mypy-aqt.fields] strict_optional = True +[mypy-aqt.filtered_deck] +strict_optional = True +[mypy-aqt.editcurrent] +strict_optional = True +[mypy-aqt.deckoptions] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/deckoptions.py b/qt/aqt/deckoptions.py index e725ddc4a..9cc3d8e45 100644 --- a/qt/aqt/deckoptions.py +++ b/qt/aqt/deckoptions.py @@ -67,9 +67,10 @@ class DeckOptionsDialog(QDialog): elif cmd == "_close": self._close() - def closeEvent(self, evt: QCloseEvent) -> None: + def closeEvent(self, evt: QCloseEvent | None) -> None: if self._close_event_has_cleaned_up: return super().closeEvent(evt) + assert evt is not None evt.ignore() self.check_pending_changes() @@ -97,7 +98,7 @@ class DeckOptionsDialog(QDialog): def reject(self) -> None: self.mw.col.set_wants_abort() self.web.cleanup() - self.web = None + self.web = None # type: ignore saveGeom(self, self.TITLE) QDialog.reject(self) @@ -112,10 +113,14 @@ def confirm_deck_then_display_options(active_card: Card | None = None) -> None: decks = [aqt.mw.col.decks.current()] if card := active_card: if card.odid and card.odid != decks[0]["id"]: - decks.append(aqt.mw.col.decks.get(card.odid)) + deck = aqt.mw.col.decks.get(card.odid) + assert deck is not None + decks.append(deck) if not any(d["id"] == card.did for d in decks): - decks.append(aqt.mw.col.decks.get(card.did)) + deck = aqt.mw.col.decks.get(card.did) + assert deck is not None + decks.append(deck) if len(decks) == 1: display_options_for_deck(decks[0]) @@ -142,13 +147,16 @@ def _deck_prompt_dialog(decks: list[DeckDict]) -> None: def display_options_for_deck_id(deck_id: DeckId) -> None: - display_options_for_deck(aqt.mw.col.decks.get(deck_id)) + deck = aqt.mw.col.decks.get(deck_id) + assert deck is not None + display_options_for_deck(deck) def display_options_for_deck(deck: DeckDict) -> None: if not deck["dyn"]: if KeyboardModifiersPressed().shift or not aqt.mw.col.v3_scheduler(): deck_legacy = aqt.mw.col.decks.get(DeckId(deck["id"])) + assert deck_legacy is not None aqt.deckconf.DeckConf(aqt.mw, deck_legacy) else: DeckOptionsDialog(aqt.mw, deck) diff --git a/qt/aqt/editcurrent.py b/qt/aqt/editcurrent.py index 9befcdeac..6f54245d2 100644 --- a/qt/aqt/editcurrent.py +++ b/qt/aqt/editcurrent.py @@ -28,10 +28,12 @@ class EditCurrent(QMainWindow): self, editor_mode=aqt.editor.EditorMode.EDIT_CURRENT, ) + assert self.mw.reviewer.card is not None self.editor.card = self.mw.reviewer.card self.editor.set_note(self.mw.reviewer.card.note(), focusTo=0) restoreGeom(self, "editcurrent") close_button = self.form.buttonBox.button(QDialogButtonBox.StandardButton.Close) + assert close_button is not None close_button.setShortcut(QKeySequence("Ctrl+Return")) # qt5.14+ doesn't handle numpad enter on Windows self.compat_add_shorcut = QShortcut(QKeySequence("Ctrl+Enter"), self) @@ -46,6 +48,7 @@ class EditCurrent(QMainWindow): # reload note note = self.editor.note try: + assert note is not None note.load() except NotFoundError: # note's been deleted @@ -65,7 +68,7 @@ class EditCurrent(QMainWindow): if card := self.mw.reviewer.card: self.editor.set_note(card.note()) - def closeEvent(self, evt: QCloseEvent) -> None: + def closeEvent(self, evt: QCloseEvent | None) -> None: self.editor.call_after_note_saved(self.cleanup) def _saveAndClose(self) -> None: diff --git a/qt/aqt/filtered_deck.py b/qt/aqt/filtered_deck.py index acda4ef86..fdf63f1d3 100644 --- a/qt/aqt/filtered_deck.py +++ b/qt/aqt/filtered_deck.py @@ -130,9 +130,10 @@ class FilteredDeckConfigDialog(QDialog): build_label = tr.actions_rebuild() else: build_label = tr.decks_build() - self.form.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText( - build_label - ) + + ok_button = self.form.buttonBox.button(QDialogButtonBox.StandardButton.Ok) + assert ok_button is not None + ok_button.setText(build_label) form.resched.setChecked(config.reschedule) self._onReschedToggled(0) From eb393aeaee41fe860598526b0e199f2f165322fa Mon Sep 17 00:00:00 2001 From: Abdo Date: Thu, 7 Nov 2024 01:35:39 +0300 Subject: [PATCH 065/113] Warn if no day is set to Normal (#3557) --- ftl/core/deck-config.ftl | 1 + ts/routes/deck-options/EasyDays.svelte | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/ftl/core/deck-config.ftl b/ftl/core/deck-config.ftl index ca34c4b1e..fe47ef824 100644 --- a/ftl/core/deck-config.ftl +++ b/ftl/core/deck-config.ftl @@ -290,6 +290,7 @@ deck-config-easy-days-sunday = Sunday deck-config-easy-days-normal = Normal deck-config-easy-days-reduced = Reduced deck-config-easy-days-minimum = Minimum +deck-config-easy-days-no-normal-days = At least one day should be set to '{ deck-config-easy-days-normal }'. ## Adding/renaming diff --git a/ts/routes/deck-options/EasyDays.svelte b/ts/routes/deck-options/EasyDays.svelte index c87c6aba8..9b4d9c2a2 100644 --- a/ts/routes/deck-options/EasyDays.svelte +++ b/ts/routes/deck-options/EasyDays.svelte @@ -8,6 +8,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import Item from "$lib/components/Item.svelte"; import TitledContainer from "$lib/components/TitledContainer.svelte"; import type { DeckOptionsState } from "./lib"; + import Warning from "./Warning.svelte"; export let state: DeckOptionsState; export let api: Record; @@ -20,6 +21,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html $config.easyDaysPercentages = defaults.easyDaysPercentages; } + $: noNormalDay = $config.easyDaysPercentages.some((p) => p === 1.0) + ? "" + : tr.deckConfigEasyDaysNoNormalDays(); + const easyDays = [ tr.deckConfigEasyDaysMonday(), tr.deckConfigEasyDaysTuesday(), @@ -81,6 +86,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
+ + + From b4ae7ce9077c92e929b002a5f738f1754ecf1fda Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 7 Nov 2024 08:37:32 +1000 Subject: [PATCH 066/113] Remove unused link --- pylib/anki/template.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pylib/anki/template.py b/pylib/anki/template.py index 2a145c9e5..3e993b9ea 100644 --- a/pylib/anki/template.py +++ b/pylib/anki/template.py @@ -43,10 +43,6 @@ from anki.models import NotetypeDict from anki.sound import AVTag, SoundOrVideoTag, TTSTag from anki.utils import to_json_bytes -CARD_BLANK_HELP = ( - "https://anki.tenderapp.com/kb/card-appearance/the-front-of-this-card-is-blank" -) - @dataclass class TemplateReplacement: From 487b38b06c016310ecf78475a0a94db5d29f4fdb Mon Sep 17 00:00:00 2001 From: Jake Probst Date: Wed, 6 Nov 2024 15:06:07 -0800 Subject: [PATCH 067/113] include backlog cards in today in future due graph (#3379) * include backlog cards in today in future due graph when backlog option is not checked * Don't add the backlog to today when backlog disabled --------- Co-authored-by: Damien Elmes --- rslib/src/stats/graphs/future_due.rs | 2 +- ts/routes/graphs/future-due.ts | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/rslib/src/stats/graphs/future_due.rs b/rslib/src/stats/graphs/future_due.rs index a98f2de5c..4f96bf8c8 100644 --- a/rslib/src/stats/graphs/future_due.rs +++ b/rslib/src/stats/graphs/future_due.rs @@ -32,7 +32,7 @@ impl GraphsContext { } // still want to filtered out buried cards that are due today - if due_day == 0 && matches!(c.queue, CardQueue::UserBuried | CardQueue::SchedBuried) { + if due_day <= 0 && matches!(c.queue, CardQueue::UserBuried | CardQueue::SchedBuried) { continue; } have_backlog |= due_day < 0; diff --git a/ts/routes/graphs/future-due.ts b/ts/routes/graphs/future-due.ts index 96a7bab7a..6100470b7 100644 --- a/ts/routes/graphs/future-due.ts +++ b/ts/routes/graphs/future-due.ts @@ -46,23 +46,33 @@ function makeQuery(start: number, end: number): string { } } +function withoutBacklog(data: Map): Map { + const map = new Map(); + for (const [day, count] of data.entries()) { + if (day >= 0) { + map.set(day, count); + } + } + return map; +} + export function buildHistogram( sourceData: GraphData, range: GraphRange, - backlog: boolean, + includeBacklog: boolean, dispatch: SearchDispatch, browserLinksSupported: boolean, ): FutureDueResponse { const output = { histogramData: null, tableData: [] }; // get min/max - const data = sourceData.dueCounts; + const data = includeBacklog ? sourceData.dueCounts : withoutBacklog(sourceData.dueCounts); if (!data) { return output; } const [xMinOrig, origXMax] = extent(data.keys()); let xMin = xMinOrig; - if (!backlog) { + if (!includeBacklog) { xMin = 0; } let xMax = origXMax; From 1f96489755688ac4c7fe2c3d05a6c791ff9475a3 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 7 Nov 2024 16:52:50 +1000 Subject: [PATCH 068/113] Fix invalid preset search matching cards in filtered decks https://forums.ankiweb.net/t/anki-24-10-release-candidate/51191/64 --- rslib/src/search/sqlwriter.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/rslib/src/search/sqlwriter.rs b/rslib/src/search/sqlwriter.rs index 97a6a29a3..7bd06dda2 100644 --- a/rslib/src/search/sqlwriter.rs +++ b/rslib/src/search/sqlwriter.rs @@ -842,8 +842,14 @@ impl SqlWriter<'_> { self.col.get_config_bool(BoolKey::IgnoreAccentsInSearch), ) } + fn write_deck_preset(&mut self, name: &str) -> Result<()> { let dcid = self.col.storage.get_deck_config_id_by_name(name)?; + if dcid.is_none() { + write!(self.sql, "false").unwrap(); + return Ok(()); + }; + let mut str_ids = String::new(); let deck_ids = self .col @@ -1284,6 +1290,13 @@ c.odue != 0 then c.odue else c.due end) != {days}) or (c.queue in (1,4) and &s(ctx, "has-cd:r").0, "(extract_custom_data(c.data, 'r') is not null)" ); + + // preset search + assert_eq!( + &s(ctx, "preset:default").0, + "((c.did in (1) or c.odid in (1)))" + ); + assert_eq!(&s(ctx, "preset:typo").0, "(false)"); } #[test] From 7f5e0810145c3067f0345651af638dad790c56e5 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 7 Nov 2024 17:05:27 +1000 Subject: [PATCH 069/113] Bump version to 24.11 --- .version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.version b/.version index 250af06b5..cd158b7c5 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -24.10 \ No newline at end of file +24.11 \ No newline at end of file From a150eda287a9b82841a367e2d675aac0acd50b62 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Fri, 8 Nov 2024 02:42:42 -0800 Subject: [PATCH 070/113] Enable strict_optional for aqt/notetypechooser, stats, switch (#3558) * Enable strict_optional for notetypechooser * Fix mypy errors * Enable strict_optional for stats * Fix mypy errors * Enable strict_optional for switch * Fix mypy errors --------- Co-authored-by: Abdo --- .mypy.ini | 6 ++++++ qt/aqt/notetypechooser.py | 5 ++++- qt/aqt/stats.py | 15 +++++++++++---- qt/aqt/switch.py | 7 ++++--- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index 93ed0aaad..6ba52ee64 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -74,6 +74,12 @@ strict_optional = True strict_optional = True [mypy-aqt.deckoptions] strict_optional = True +[mypy-aqt.notetypechooser] +strict_optional = True +[mypy-aqt.stats] +strict_optional = True +[mypy-aqt.switch] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/notetypechooser.py b/qt/aqt/notetypechooser.py index 395af193b..cb282109d 100644 --- a/qt/aqt/notetypechooser.py +++ b/qt/aqt/notetypechooser.py @@ -111,6 +111,7 @@ class NotetypeChooser(QHBoxLayout): if not ret.name: return notetype = self.mw.col.models.by_name(ret.name) + assert notetype is not None if (id := notetype["id"]) != self._selected_notetype_id: self.selected_notetype_id = id @@ -146,7 +147,9 @@ class NotetypeChooser(QHBoxLayout): func(self._selected_notetype_id) def selected_notetype_name(self) -> str: - return self.mw.col.models.get(self.selected_notetype_id)["name"] + selected_notetype = self.mw.col.models.get(self.selected_notetype_id) + assert selected_notetype is not None + return selected_notetype["name"] def _ensure_selected_notetype_valid(self) -> None: if not self.mw.col.models.get(self._selected_notetype_id): diff --git a/qt/aqt/stats.py b/qt/aqt/stats.py index 206205349..05caf97f2 100644 --- a/qt/aqt/stats.py +++ b/qt/aqt/stats.py @@ -61,9 +61,11 @@ class NewDeckStats(QDialog): b = f.buttonBox.addButton( tr.statistics_save_pdf(), QDialogButtonBox.ButtonRole.ActionRole ) + assert b is not None qconnect(b.clicked, self.saveImage) b.setAutoDefault(False) b = f.buttonBox.button(QDialogButtonBox.StandardButton.Close) + assert b is not None b.setAutoDefault(False) maybeHideClose(self.form.buttonBox) addCloseShortcut(self) @@ -78,7 +80,7 @@ class NewDeckStats(QDialog): def reject(self) -> None: self.deck_chooser.cleanup() self.form.web.cleanup() - self.form.web = None + self.form.web = None # type: ignore saveGeom(self, self.name) aqt.dialogs.markClosed("NewDeckStats") QDialog.reject(self) @@ -115,7 +117,9 @@ class NewDeckStats(QDialog): # unreadable. A simple fix for now is to scroll to the top of the # page first. def after_scroll(arg: Any) -> None: - self.form.web.page().printToPdf(path) + form_web_page = self.form.web.page() + assert form_web_page is not None + form_web_page.printToPdf(path) tooltip(tr.statistics_saved()) self.form.web.evalWithCallback("window.scrollTo(0, 0);", after_scroll) @@ -165,6 +169,7 @@ class DeckStats(QDialog): b = f.buttonBox.addButton( tr.statistics_save_pdf(), QDialogButtonBox.ButtonRole.ActionRole ) + assert b is not None qconnect(b.clicked, self.saveImage) b.setAutoDefault(False) qconnect(f.groups.clicked, lambda: self.changeScope("deck")) @@ -182,7 +187,7 @@ class DeckStats(QDialog): def reject(self) -> None: self.form.web.cleanup() - self.form.web = None + self.form.web = None # type: ignore saveGeom(self, self.name) aqt.dialogs.markClosed("DeckStats") QDialog.reject(self) @@ -208,7 +213,9 @@ class DeckStats(QDialog): path = self._imagePath() if not path: return - self.form.web.page().printToPdf(path) + form_web_page = self.form.web.page() + assert form_web_page is not None + form_web_page.printToPdf(path) tooltip(tr.statistics_saved()) def changePeriod(self, n: int) -> None: diff --git a/qt/aqt/switch.py b/qt/aqt/switch.py index fb3c2da6c..214d20bc7 100644 --- a/qt/aqt/switch.py +++ b/qt/aqt/switch.py @@ -103,7 +103,7 @@ class Switch(QAbstractButton): self._position = self.end_position self.update() - def paintEvent(self, _event: QPaintEvent) -> None: + def paintEvent(self, _event: QPaintEvent | None) -> None: painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) painter.setPen(Qt.PenStyle.NoPen) @@ -162,12 +162,13 @@ class Switch(QAbstractButton): self._current_label_rectangle(), Qt.AlignmentFlag.AlignCenter, self.label ) - def mouseReleaseEvent(self, event: QMouseEvent) -> None: + def mouseReleaseEvent(self, event: QMouseEvent | None) -> None: super().mouseReleaseEvent(event) + assert event is not None if event.button() == Qt.MouseButton.LeftButton: self._animate_toggle() - def enterEvent(self, event: QEnterEvent) -> None: + def enterEvent(self, event: QEnterEvent | None) -> None: self.setCursor(Qt.CursorShape.PointingHandCursor) super().enterEvent(event) From b646f09c686819db6db9b42228bdaf041ac8eacb Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 8 Nov 2024 22:53:13 +1000 Subject: [PATCH 071/113] Add descending retrievability (#3559) * "relative overdueness" -> "retrievability ascending" * Add 'retrievability descending' --- ftl/core/deck-config.ftl | 4 ++- ftl/core/decks.ftl | 6 +++- proto/anki/deck_config.proto | 3 +- proto/anki/decks.proto | 3 +- rslib/src/decks/filtered.rs | 7 +++- rslib/src/scheduler/queue/builder/mod.rs | 2 +- rslib/src/storage/card/filtered.rs | 45 +++++++++++++++-------- rslib/src/storage/card/mod.rs | 46 ++++++++++++++++-------- rslib/src/storage/sqlite.rs | 33 +++++++++++++---- ts/routes/deck-options/choices.ts | 8 +++-- 10 files changed, 115 insertions(+), 42 deletions(-) diff --git a/ftl/core/deck-config.ftl b/ftl/core/deck-config.ftl index fe47ef824..0b1ef775f 100644 --- a/ftl/core/deck-config.ftl +++ b/ftl/core/deck-config.ftl @@ -209,7 +209,9 @@ deck-config-sort-order-ascending-ease = Ascending ease deck-config-sort-order-descending-ease = Descending ease deck-config-sort-order-ascending-difficulty = Easy cards first deck-config-sort-order-descending-difficulty = Difficult cards first -deck-config-sort-order-relative-overdueness = Relative overdueness +deck-config-sort-order-retrievability-ascending = Ascending retrievability +deck-config-sort-order-retrievability-descending = Descending retrievability + deck-config-display-order-will-use-current-deck = Anki will use the display order from the deck you select to study, and not any subdecks it may have. diff --git a/ftl/core/decks.ftl b/ftl/core/decks.ftl index e4369884b..48ecdb569 100644 --- a/ftl/core/decks.ftl +++ b/ftl/core/decks.ftl @@ -24,7 +24,6 @@ decks-order-added = Order added decks-order-due = Order due decks-please-select-something = Please select something. decks-random = Random -decks-relative-overdueness = Relative overdueness decks-repeat-failed-cards-after = Delay Repeat failed cards after # e.g. "Delay for Again", "Delay for Hard", "Delay for Good" decks-delay-for-button = Delay for { $button } @@ -37,3 +36,8 @@ decks-learn-header = Learn # The count of cards waiting to be reviewed decks-review-header = Due decks-zero-minutes-hint = (0 = return card to original deck) + +## These strings are no longer used - you do not need to translate them if they +## are not already translated. + +decks-relative-overdueness = Relative overdueness diff --git a/proto/anki/deck_config.proto b/proto/anki/deck_config.proto index c3fc5298b..efd8a80d0 100644 --- a/proto/anki/deck_config.proto +++ b/proto/anki/deck_config.proto @@ -79,7 +79,8 @@ message DeckConfig { REVIEW_CARD_ORDER_INTERVALS_DESCENDING = 4; REVIEW_CARD_ORDER_EASE_ASCENDING = 5; REVIEW_CARD_ORDER_EASE_DESCENDING = 6; - REVIEW_CARD_ORDER_RELATIVE_OVERDUENESS = 7; + REVIEW_CARD_ORDER_RETRIEVABILITY_ASCENDING = 7; + REVIEW_CARD_ORDER_RETRIEVABILITY_DESCENDING = 11; REVIEW_CARD_ORDER_RANDOM = 8; REVIEW_CARD_ORDER_ADDED = 9; REVIEW_CARD_ORDER_REVERSE_ADDED = 10; diff --git a/proto/anki/decks.proto b/proto/anki/decks.proto index c91abb39a..bcd206b06 100644 --- a/proto/anki/decks.proto +++ b/proto/anki/decks.proto @@ -97,7 +97,8 @@ message Deck { ADDED = 5; DUE = 6; REVERSE_ADDED = 7; - DUE_PRIORITY = 8; + RETRIEVABILITY_ASCENDING = 8; + RETRIEVABILITY_DESCENDING = 9; } string search = 1; diff --git a/rslib/src/decks/filtered.rs b/rslib/src/decks/filtered.rs index dcc8585bb..ef77076af 100644 --- a/rslib/src/decks/filtered.rs +++ b/rslib/src/decks/filtered.rs @@ -60,7 +60,12 @@ fn search_order_label(order: FilteredSearchOrder, tr: &I18n) -> String { FilteredSearchOrder::Added => tr.decks_order_added(), FilteredSearchOrder::Due => tr.decks_order_due(), FilteredSearchOrder::ReverseAdded => tr.decks_latest_added_first(), - FilteredSearchOrder::DuePriority => tr.decks_relative_overdueness(), + FilteredSearchOrder::RetrievabilityAscending => { + tr.deck_config_sort_order_retrievability_ascending() + } + FilteredSearchOrder::RetrievabilityDescending => { + tr.deck_config_sort_order_retrievability_descending() + } } .into() } diff --git a/rslib/src/scheduler/queue/builder/mod.rs b/rslib/src/scheduler/queue/builder/mod.rs index a95d056a8..c707f8df1 100644 --- a/rslib/src/scheduler/queue/builder/mod.rs +++ b/rslib/src/scheduler/queue/builder/mod.rs @@ -464,7 +464,7 @@ mod test { cards.push(card); } col.update_cards_maybe_undoable(cards, false)?; - col.set_deck_review_order(&mut deck, ReviewCardOrder::RelativeOverdueness); + col.set_deck_review_order(&mut deck, ReviewCardOrder::RetrievabilityAscending); assert_eq!(col.queue_as_due_and_ivl(deck.id), expected_queue); Ok(()) diff --git a/rslib/src/storage/card/filtered.rs b/rslib/src/storage/card/filtered.rs index b4668bbec..8443c2e18 100644 --- a/rslib/src/storage/card/filtered.rs +++ b/rslib/src/storage/card/filtered.rs @@ -5,6 +5,7 @@ use crate::card::CardQueue; use crate::decks::FilteredSearchOrder; use crate::decks::FilteredSearchTerm; use crate::scheduler::timing::SchedTimingToday; +use crate::storage::sqlite::SqlSortOrder; pub(crate) fn order_and_limit_for_search( term: &FilteredSearchTerm, @@ -27,24 +28,40 @@ pub(crate) fn order_and_limit_for_search( "(case when c.due > 1000000000 then due else (due - {today}) * 86400 + {current_timestamp} end), c.ord"); &temp_string } - FilteredSearchOrder::DuePriority => { + FilteredSearchOrder::RetrievabilityAscending => { let next_day_at = timing.next_day_at.0; - temp_string = if fsrs { - format!( - "extract_fsrs_relative_overdueness(c.data, due, {today}, ivl, {next_day_at}) desc" - ) - } else { - format!( - " -(case when queue={rev_queue} and due <= {today} -then (ivl / cast({today}-due+0.001 as real)) else 100000+due end)", - rev_queue = CardQueue::Review as i8, - today = today - ) - }; + temp_string = + build_retrievability_query(fsrs, today, next_day_at, SqlSortOrder::Ascending); + &temp_string + } + FilteredSearchOrder::RetrievabilityDescending => { + let next_day_at = timing.next_day_at.0; + temp_string = + build_retrievability_query(fsrs, today, next_day_at, SqlSortOrder::Descending); &temp_string } }; format!("{}, fnvhash(c.id, c.mod) limit {}", order, term.limit) } + +fn build_retrievability_query( + fsrs: bool, + today: u32, + next_day_at: i64, + order: SqlSortOrder, +) -> String { + if fsrs { + format!( + "extract_fsrs_relative_retrievability(c.data, due, {today}, ivl, {next_day_at}) {order}" + ) + } else { + format!( + " +(case when queue={rev_queue} and due <= {today} +then (ivl / cast({today}-due+0.001 as real)) else 100000+due end) {order}", + rev_queue = CardQueue::Review as i8, + today = today + ) + } +} diff --git a/rslib/src/storage/card/mod.rs b/rslib/src/storage/card/mod.rs index 51263a8b1..812691523 100644 --- a/rslib/src/storage/card/mod.rs +++ b/rslib/src/storage/card/mod.rs @@ -20,6 +20,7 @@ use rusqlite::Row; use self::data::CardData; use super::ids_to_string; +use super::sqlite::SqlSortOrder; use crate::card::Card; use crate::card::CardId; use crate::card::CardQueue; @@ -747,11 +748,13 @@ enum ReviewOrderSubclause { DifficultyAscending, /// FSRS DifficultyDescending, - RelativeOverdueness { + RetrievabilitySm2 { today: u32, + order: SqlSortOrder, }, - RelativeOverduenessFsrs { + RetrievabilityFsrs { timing: SchedTimingToday, + order: SqlSortOrder, }, Added, ReverseAdded, @@ -770,15 +773,18 @@ impl fmt::Display for ReviewOrderSubclause { ReviewOrderSubclause::EaseDescending => "factor desc", ReviewOrderSubclause::DifficultyAscending => "extract_fsrs_variable(data, 'd') asc", ReviewOrderSubclause::DifficultyDescending => "extract_fsrs_variable(data, 'd') desc", - ReviewOrderSubclause::RelativeOverdueness { today } => { - temp_string = format!("ivl / cast({today}-due+0.001 as real)", today = today); + ReviewOrderSubclause::RetrievabilitySm2 { today, order } => { + temp_string = format!( + "ivl / cast({today}-due+0.001 as real) {order}", + today = today + ); &temp_string } - ReviewOrderSubclause::RelativeOverduenessFsrs { timing } => { + ReviewOrderSubclause::RetrievabilityFsrs { timing, order } => { let today = timing.days_elapsed; let next_day_at = timing.next_day_at.0; temp_string = - format!("extract_fsrs_relative_overdueness(data, due, {today}, ivl, {next_day_at}) desc"); + format!("extract_fsrs_relative_retrievability(data, due, {today}, ivl, {next_day_at}) {order}"); &temp_string } ReviewOrderSubclause::Added => "nid asc, ord asc", @@ -807,14 +813,11 @@ fn review_order_sql(order: ReviewCardOrder, timing: SchedTimingToday, fsrs: bool } else { ReviewOrderSubclause::EaseDescending }], - ReviewCardOrder::RelativeOverdueness => { - vec![if fsrs { - ReviewOrderSubclause::RelativeOverduenessFsrs { timing } - } else { - ReviewOrderSubclause::RelativeOverdueness { - today: timing.days_elapsed, - } - }] + ReviewCardOrder::RetrievabilityAscending => { + build_retrievability_clauses(fsrs, timing, SqlSortOrder::Ascending) + } + ReviewCardOrder::RetrievabilityDescending => { + build_retrievability_clauses(fsrs, timing, SqlSortOrder::Descending) } ReviewCardOrder::Random => vec![], ReviewCardOrder::Added => vec![ReviewOrderSubclause::Added], @@ -829,6 +832,21 @@ fn review_order_sql(order: ReviewCardOrder, timing: SchedTimingToday, fsrs: bool v.join(", ") } +fn build_retrievability_clauses( + fsrs: bool, + timing: SchedTimingToday, + order: SqlSortOrder, +) -> Vec { + vec![if fsrs { + ReviewOrderSubclause::RetrievabilityFsrs { timing, order } + } else { + ReviewOrderSubclause::RetrievabilitySm2 { + today: timing.days_elapsed, + order, + } + }] +} + #[derive(Debug, Clone, Copy)] pub(crate) enum NewCardSorting { /// Ascending position, consecutive siblings, diff --git a/rslib/src/storage/sqlite.rs b/rslib/src/storage/sqlite.rs index 42d46c520..37ea06cb5 100644 --- a/rslib/src/storage/sqlite.rs +++ b/rslib/src/storage/sqlite.rs @@ -4,6 +4,7 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::collections::HashSet; +use std::fmt::Display; use std::hash::Hasher; use std::path::Path; use std::sync::Arc; @@ -74,7 +75,7 @@ fn open_or_create_collection_db(path: &Path) -> Result { add_extract_custom_data_function(&db)?; add_extract_fsrs_variable(&db)?; add_extract_fsrs_retrievability(&db)?; - add_extract_fsrs_relative_overdueness(&db)?; + add_extract_fsrs_relative_retrievability(&db)?; db.create_collation("unicase", unicase_compare)?; @@ -333,12 +334,13 @@ fn add_extract_fsrs_retrievability(db: &Connection) -> rusqlite::Result<()> { ) } -/// eg. extract_fsrs_relative_overdueness(card.data, card.due, +/// eg. extract_fsrs_relative_retrievability(card.data, card.due, /// timing.days_elapsed, card.ivl, timing.next_day_at) -> float | null. The -/// higher the number, the more overdue. -fn add_extract_fsrs_relative_overdueness(db: &Connection) -> rusqlite::Result<()> { +/// higher the number, the higher the card's retrievability relative to the +/// configured desired retention. +fn add_extract_fsrs_relative_retrievability(db: &Connection) -> rusqlite::Result<()> { db.create_scalar_function( - "extract_fsrs_relative_overdueness", + "extract_fsrs_relative_retrievability", 5, FunctionFlags::SQLITE_DETERMINISTIC, move |ctx| { @@ -386,7 +388,7 @@ fn add_extract_fsrs_relative_overdueness(db: &Connection) -> rusqlite::Result<() .max(0.0001); Ok(Some( - (1. / current_retrievability - 1.) / (1. / desired_retrievability - 1.), + -(1. / current_retrievability - 1.) / (1. / desired_retrievability - 1.), )) }, ) @@ -590,3 +592,22 @@ impl SqliteStorage { self.db.query_row(sql, [], |r| r.get(0)).map_err(Into::into) } } + +#[derive(Debug, Clone, Copy)] +pub enum SqlSortOrder { + Ascending, + Descending, +} + +impl Display for SqlSortOrder { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + SqlSortOrder::Ascending => "asc", + SqlSortOrder::Descending => "desc", + } + ) + } +} diff --git a/ts/routes/deck-options/choices.ts b/ts/routes/deck-options/choices.ts index 0b4611528..6f34eae0e 100644 --- a/ts/routes/deck-options/choices.ts +++ b/ts/routes/deck-options/choices.ts @@ -96,8 +96,12 @@ export function reviewOrderChoices(fsrs: boolean): Choice Date: Fri, 8 Nov 2024 18:23:57 +0530 Subject: [PATCH 072/113] Move to all "Note type" (#3560) * update change-notetype.ftl * update notetypes.ftl * update errors.ftl * update adding.ftl * update actions.ftl * update browsing.ftl * update exporting.ftl * update importing.ftl * update card-templates.ftl * update database-check.ftl * fix casing * Update ftl/core/adding.ftl Co-authored-by: Abdo --------- Co-authored-by: Abdo --- ftl/core/actions.ftl | 6 +++--- ftl/core/adding.ftl | 4 ++-- ftl/core/browsing.ftl | 4 ++-- ftl/core/card-templates.ftl | 8 ++++---- ftl/core/change-notetype.ftl | 4 ++-- ftl/core/database-check.ftl | 2 +- ftl/core/errors.ftl | 2 +- ftl/core/exporting.ftl | 2 +- ftl/core/importing.ftl | 36 ++++++++++++++++++------------------ ftl/core/notetypes.ftl | 2 +- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/ftl/core/actions.ftl b/ftl/core/actions.ftl index 82c31e1ed..8fd3df0f7 100644 --- a/ftl/core/actions.ftl +++ b/ftl/core/actions.ftl @@ -48,9 +48,9 @@ actions-update-card = Update Card actions-update-deck = Update Deck actions-forget-card = Reset Card actions-build-filtered-deck = Build Deck -actions-add-notetype = Add Notetype -actions-remove-notetype = Remove Notetype -actions-update-notetype = Update Notetype +actions-add-notetype = Add Note Type +actions-remove-notetype = Remove Note Type +actions-update-notetype = Update Note Type actions-update-config = Update Config actions-card-info = Card Info actions-previous-card-info = Previous Card Info diff --git a/ftl/core/adding.ftl b/ftl/core/adding.ftl index b95210ee9..e94333008 100644 --- a/ftl/core/adding.ftl +++ b/ftl/core/adding.ftl @@ -7,6 +7,6 @@ adding-history = History adding-note-deleted = (Note deleted) adding-shortcut = Shortcut: { $val } adding-the-first-field-is-empty = The first field is empty. -adding-you-have-a-cloze-deletion-note = You have a cloze notetype but have not made any cloze deletions. Proceed? -adding-cloze-outside-cloze-notetype = Cloze deletion can only be used on cloze notetypes. +adding-you-have-a-cloze-deletion-note = You have a cloze note type but have not made any cloze deletions. Proceed? +adding-cloze-outside-cloze-notetype = Cloze deletion can only be used on cloze note types. adding-cloze-outside-cloze-field = Cloze deletion can only be used in fields which use the 'cloze:' filter. This is typically the first field. diff --git a/ftl/core/browsing.ftl b/ftl/core/browsing.ftl index 644d158ac..c04d3c8e9 100644 --- a/ftl/core/browsing.ftl +++ b/ftl/core/browsing.ftl @@ -29,7 +29,7 @@ browsing-change-deck = Change Deck browsing-change-deck2 = Change Deck... browsing-change-note-type = Change Note Type browsing-change-note-type2 = Change Note Type... -browsing-change-notetype = Change Notetype +browsing-change-notetype = Change Note Type browsing-clear-unused-tags = Clear Unused Tags browsing-confirm-saved-search-overwrite = A saved search with the name { $name } already exists. Do you want to overwrite it? browsing-created = Created @@ -142,7 +142,7 @@ browsing-tooltip-card-modified = The last time changes were made to a card, incl browsing-tooltip-note-modified = The last time changes were made to a note, usually field content or tag edits browsing-tooltip-card = The name of a card's card template browsing-tooltip-cards = The number of cards a note has -browsing-tooltip-notetype = The name of a note's notetype +browsing-tooltip-notetype = The name of a note's note type browsing-tooltip-question = The front side of a card, customisable in the card template editor browsing-tooltip-answer = The back side of a card, customisable in the card template editor browsing-studied-today = Studied diff --git a/ftl/core/card-templates.ftl b/ftl/core/card-templates.ftl index b61fcec90..18a7a76b4 100644 --- a/ftl/core/card-templates.ftl +++ b/ftl/core/card-templates.ftl @@ -20,11 +20,11 @@ card-templates-night-mode = Night Mode # on a mobile device. card-templates-add-mobile-class = Add Mobile Class card-templates-preview-settings = Options -card-templates-invalid-template-number = Card template { $number } in notetype '{ $notetype }' has a problem. +card-templates-invalid-template-number = Card template { $number } in note type '{ $notetype }' has a problem. card-templates-identical-front = The front side is identical to card template { $number }. card-templates-no-front-field = Expected to find a field replacement on the front of the card template. card-templates-missing-cloze = Expected to find '{ "{{" }cloze:Text{ "}}" }' or similar on the front and back of the card template. -card-templates-extraneous-cloze = 'cloze:' can only be used on cloze notetypes. +card-templates-extraneous-cloze = 'cloze:' can only be used on cloze note types. card-templates-see-preview = See the preview for more information. card-templates-field-not-found = Field '{ $field }' not found. card-templates-changes-saved = Changes saved. @@ -59,7 +59,7 @@ card-templates-this-will-create-card-proceed = } card-templates-type-boxes-warning = Only one typing box per card template is supported. card-templates-restore-to-default = Restore to Default -card-templates-restore-to-default-confirmation = This will reset all fields and templates in this notetype to their default +card-templates-restore-to-default-confirmation = This will reset all fields and templates in this note type to their default values, removing any extra fields/templates and their content, and any custom styling. Do you wish to proceed? -card-templates-restored-to-default = Notetype has been restored to its original state. +card-templates-restored-to-default = Note type has been restored to its original state. diff --git a/ftl/core/change-notetype.ftl b/ftl/core/change-notetype.ftl index 419030389..f21abd3d2 100644 --- a/ftl/core/change-notetype.ftl +++ b/ftl/core/change-notetype.ftl @@ -8,7 +8,7 @@ change-notetype-will-discard-cards = Will remove the following cards: change-notetype-fields = Fields change-notetype-templates = Templates change-notetype-to-from-cloze = - When changing to or from a Cloze notetype, card numbers remain unchanged. + When changing to or from a Cloze note type, card numbers remain unchanged. - If changing to a regular notetype, and there are more cloze deletions + If changing to a regular note type, and there are more cloze deletions than available card templates, any extra cards will be removed. diff --git a/ftl/core/database-check.ftl b/ftl/core/database-check.ftl index 67d6812e7..8a9e4e178 100644 --- a/ftl/core/database-check.ftl +++ b/ftl/core/database-check.ftl @@ -51,7 +51,7 @@ database-check-fixed-invalid-ids = *[other] Fixed { $count } objects with timestamps in the future. } # "db-check" is always in English -database-check-notetypes-recovered = One or more notetypes were missing. The notes that used them have been given new notetypes starting with "db-check", but field names and card design have been lost, so you may be better off restoring from an automatic backup. +database-check-notetypes-recovered = One or more note types were missing. The notes that used them have been given new note types starting with "db-check", but field names and card design have been lost, so you may be better off restoring from an automatic backup. ## Progress info diff --git a/ftl/core/errors.ftl b/ftl/core/errors.ftl index c3f5a3b18..65ee5365b 100644 --- a/ftl/core/errors.ftl +++ b/ftl/core/errors.ftl @@ -5,7 +5,7 @@ errors-100-tags-max = A maximum of 100 tags can be selected. Listing the tags you want instead of the ones you don't want is usually simpler, and there is no need to select child tags if you have selected a parent tag. -errors-multiple-notetypes-selected = Please select notes from only one notetype. +errors-multiple-notetypes-selected = Please select notes from only one note type. errors-please-check-database = Please use the Check Database action, then try again. errors-please-check-media = Please use the Check Media action, then try again. errors-collection-too-new = This collection requires a newer version of Anki to open. diff --git a/ftl/core/exporting.ftl b/ftl/core/exporting.ftl index be612f7da..422a580e4 100644 --- a/ftl/core/exporting.ftl +++ b/ftl/core/exporting.ftl @@ -40,5 +40,5 @@ exporting-processed-media-files = *[other] Processed { $count } media files... } exporting-include-deck = Include deck name -exporting-include-notetype = Include notetype name +exporting-include-notetype = Include note type name exporting-include-guid = Include unique identifier diff --git a/ftl/core/importing.ftl b/ftl/core/importing.ftl index 0987818e1..bf3162809 100644 --- a/ftl/core/importing.ftl +++ b/ftl/core/importing.ftl @@ -8,7 +8,7 @@ importing-anki2-files-are-not-directly-importable = .anki2 files are not directl importing-appeared-twice-in-file = Appeared twice in file: { $val } importing-by-default-anki-will-detect-the = By default, Anki will detect the character between fields, such as a tab, comma, and so on. If Anki is detecting the character incorrectly, you can enter it here. Use \t to represent tab. importing-cannot-merge-notetypes-of-different-kinds = - Cloze notetypes cannot be merged with regular notetypes. + Cloze note types cannot be merged with regular note types. You may still import the file with '{ importing-merge-notetypes }' disabled. importing-change = Change importing-colon = Colon @@ -33,13 +33,13 @@ importing-map-to = Map to { $val } importing-map-to-tags = Map to Tags importing-mapped-to = mapped to { $val } importing-mapped-to-tags = mapped to Tags -# the action of combining two existing notetypes to create a new one -importing-merge-notetypes = Merge notetypes +# the action of combining two existing note types to create a new one +importing-merge-notetypes = Merge note types importing-merge-notetypes-help = - If checked, and you or the deck author altered the schema of a notetype, Anki will + If checked, and you or the deck author altered the schema of a note type, Anki will merge the two versions instead of keeping both. - Altering a notetype's schema means adding, removing, or reordering fields or templates, + Altering a note type's schema means adding, removing, or reordering fields or templates, or changing the sort field. As a counterexample, changing the front side of an existing template does *not* constitute a schema change. @@ -50,7 +50,7 @@ importing-multicharacter-separators-are-not-supported-please = Multi-character s importing-notes-added-from-file = Notes added from file: { $val } importing-notes-found-in-file = Notes found in file: { $val } importing-notes-skipped-as-theyre-already-in = Notes skipped, as up-to-date copies are already in your collection: { $val } -importing-notes-skipped-update-due-to-notetype = Notes not updated, as notetype has been modified since you first imported the notes: { $val } +importing-notes-skipped-update-due-to-notetype = Notes not updated, as note type has been modified since you first imported the notes: { $val } importing-notes-updated-as-file-had-newer = Notes updated, as file had newer version: { $val } importing-include-reviews = Include reviews importing-also-import-progress = Import any learning progress @@ -90,10 +90,10 @@ importing-update-notes = Update notes importing-update-notes-help = When to update an existing note in your collection. By default, this is only done if the matching imported note was more recently modified. -importing-update-notetypes = Update notetypes +importing-update-notetypes = Update note types importing-update-notetypes-help = - When to update an existing notetype in your collection. By default, this is only done - if the matching imported notetype was more recently modified. Changes to template text + When to update an existing note type in your collection. By default, this is only done + if the matching imported note type was more recently modified. Changes to template text and styling can always be imported, but for schema changes (e.g. the number or order of fields has changed), the '{ importing-merge-notetypes }' option will also need to be enabled. importing-note-added = @@ -148,7 +148,7 @@ importing-file = File # "Match scope: notetype / notetype and deck". Controls how duplicates are matched. importing-match-scope = Match scope # Used with the 'match scope' option -importing-notetype-and-deck = Notetype and deck +importing-notetype-and-deck = Note type and deck importing-cards-added = { $count -> [one] { $count } card added. @@ -182,8 +182,8 @@ importing-conflicting-notes-skipped = } importing-conflicting-notes-skipped2 = { $count -> - [one] { $count } note was not imported, because its notetype has changed, and '{ importing-merge-notetypes }' was not enabled. - *[other] { $count } notes were not imported, because their notetype has changed, and '{ importing-merge-notetypes }' was not enabled. + [one] { $count } note was not imported, because its note type has changed, and '{ importing-merge-notetypes }' was not enabled. + *[other] { $count } notes were not imported, because their note type has changed, and '{ importing-merge-notetypes }' was not enabled. } importing-import-log = Import Log importing-no-notes-in-file = No notes found in file. @@ -198,8 +198,8 @@ importing-status = Status importing-duplicate-note-added = Duplicate note added importing-added-new-note = New note added importing-existing-note-skipped = Note skipped, as an up-to-date copy is already in your collection -importing-note-skipped-update-due-to-notetype = Note not updated, as notetype has been modified since you first imported the note -importing-note-skipped-update-due-to-notetype2 = Note not updated, as notetype has been modified since you first imported the note, and '{ importing-merge-notetypes }' was not enabled +importing-note-skipped-update-due-to-notetype = Note not updated, as note type has been modified since you first imported the note +importing-note-skipped-update-due-to-notetype2 = Note not updated, as note type has been modified since you first imported the note, and '{ importing-merge-notetypes }' was not enabled importing-note-updated-as-file-had-newer = Note updated, as file had newer version importing-note-skipped-due-to-missing-notetype = Note skipped, as its notetype was missing importing-note-skipped-due-to-missing-deck = Note skipped, as its deck was missing @@ -216,10 +216,10 @@ importing-allow-html-in-fields-help = '<br>', it will appear as a line break on your card. On the other hand, with this option disabled, the literal characters '<br>' will be rendered. importing-notetype-help = - Newly-imported notes will have this notetype, and only existing notes with this - notetype will be updated. + Newly-imported notes will have this note type, and only existing notes with this + note type will be updated. - You can choose which fields in the file correspond to which notetype fields with the + You can choose which fields in the file correspond to which note type fields with the mapping tool. importing-deck-help = Imported cards will be placed in this deck. importing-existing-notes-help = @@ -229,7 +229,7 @@ importing-existing-notes-help = - `{ importing-preserve }`: Do nothing. - `{ importing-duplicate }`: Create a new note. importing-match-scope-help = - Only existing notes with the same notetype will be checked for duplicates. This can + Only existing notes with the same note type will be checked for duplicates. This can additionally be restricted to notes with cards in the same deck. importing-tag-all-notes-help = These tags will be added to both newly-imported and updated notes. diff --git a/ftl/core/notetypes.ftl b/ftl/core/notetypes.ftl index 665b9f409..f7eccd08b 100644 --- a/ftl/core/notetypes.ftl +++ b/ftl/core/notetypes.ftl @@ -1,4 +1,4 @@ -notetypes-notetype = Notetype +notetypes-notetype = Note Type ## Default field names in newly created note types From ba1f5f46c6e73dbbe8ebe3bef12233c2c08eec4f Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 8 Nov 2024 22:51:16 +1000 Subject: [PATCH 073/113] Flag server messages so AnkiDroid can handle them separately --- proto/anki/backend.proto | 1 + rslib/src/backend/error.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/proto/anki/backend.proto b/proto/anki/backend.proto index 9a3cab781..36098ab8b 100644 --- a/proto/anki/backend.proto +++ b/proto/anki/backend.proto @@ -30,6 +30,7 @@ message BackendError { DB_ERROR = 5; NETWORK_ERROR = 6; SYNC_AUTH_ERROR = 7; + SYNC_SERVER_MESSAGE = 23; SYNC_OTHER_ERROR = 8; JSON_ERROR = 9; PROTO_ERROR = 10; diff --git a/rslib/src/backend/error.rs b/rslib/src/backend/error.rs index 270a2f703..c538ec1f7 100644 --- a/rslib/src/backend/error.rs +++ b/rslib/src/backend/error.rs @@ -66,6 +66,7 @@ impl From for Kind { fn from(err: SyncErrorKind) -> Self { match err { SyncErrorKind::AuthFailed => Kind::SyncAuthError, + SyncErrorKind::ServerMessage => Kind::SyncServerMessage, _ => Kind::SyncOtherError, } } From 97e6b3d35b9ef541865a127fc094f521e43480d9 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 8 Nov 2024 22:54:26 +1000 Subject: [PATCH 074/113] Update translations --- ftl/core-repo | 2 +- ftl/qt-repo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ftl/core-repo b/ftl/core-repo index 05e08f99c..21341e091 160000 --- a/ftl/core-repo +++ b/ftl/core-repo @@ -1 +1 @@ -Subproject commit 05e08f99cd97b9cf5d7c0cfd653ad98c53a7715a +Subproject commit 21341e091b32eb8409a4d7184edf98dd4729f83a diff --git a/ftl/qt-repo b/ftl/qt-repo index b265e151a..83b9ffafa 160000 --- a/ftl/qt-repo +++ b/ftl/qt-repo @@ -1 +1 @@ -Subproject commit b265e151a8f9a77dbb061257d32739c5db2a4be2 +Subproject commit 83b9ffafac9872c10f66284e916202e5c863e50e From 748aa0f07a22bfc243943675e0aa6eddfbfe2aba Mon Sep 17 00:00:00 2001 From: Abdo Date: Sat, 9 Nov 2024 04:05:26 +0300 Subject: [PATCH 075/113] Bump AnkiHub API version (#3564) --- rslib/src/ankihub/http_client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rslib/src/ankihub/http_client/mod.rs b/rslib/src/ankihub/http_client/mod.rs index e5e374463..00d275c90 100644 --- a/rslib/src/ankihub/http_client/mod.rs +++ b/rslib/src/ankihub/http_client/mod.rs @@ -11,7 +11,7 @@ use serde::Serialize; use crate::ankihub::login::LoginRequest; -static API_VERSION: &str = "18.0"; +static API_VERSION: &str = "19.0"; static DEFAULT_API_URL: &str = "https://app.ankihub.net/api/"; #[derive(Clone)] From fdaad7150eff79f182b363698c17f1b9c06442bb Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Sat, 9 Nov 2024 02:43:51 -0800 Subject: [PATCH 076/113] Enable strict_optional for aqt/debug_console, emptycards, flags (#3565) * Enable strict_optional for debug_console * Fix mypy errors * Enable strict_optional for emptycards * Fix mypy errors * Enable strict_optional for flags * Fix mypy errors --- .mypy.ini | 6 ++++++ qt/aqt/debug_console.py | 4 +++- qt/aqt/emptycards.py | 3 ++- qt/aqt/flags.py | 6 +++--- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index 6ba52ee64..da2daea54 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -80,6 +80,12 @@ strict_optional = True strict_optional = True [mypy-aqt.switch] strict_optional = True +[mypy-aqt.debug_console] +strict_optional = True +[mypy-aqt.emptycards] +strict_optional = True +[mypy-aqt.flags] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/debug_console.py b/qt/aqt/debug_console.py index 76fead38b..2ad9843db 100644 --- a/qt/aqt/debug_console.py +++ b/qt/aqt/debug_console.py @@ -196,6 +196,7 @@ class DebugConsole(QDialog): def _on_context_menu(self, text_edit: QPlainTextEdit) -> None: menu = text_edit.createStandardContextMenu() + assert menu is not None menu.addSeparator() for action in self._actions(): entry = menu.addAction(action.name) @@ -227,7 +228,7 @@ class DebugConsole(QDialog): sys.stderr = self._oldStderr sys.stdout = self._oldStdout - def _card_repr(self, card: anki.cards.Card) -> None: + def _card_repr(self, card: anki.cards.Card | None) -> None: import copy import pprint @@ -316,6 +317,7 @@ class DebugConsole(QDialog): ) self._log.appendPlainText(to_append) slider = self._log.verticalScrollBar() + assert slider is not None slider.setValue(slider.maximum()) self._log.ensureCursorVisible() diff --git a/qt/aqt/emptycards.py b/qt/aqt/emptycards.py index 378aa09c3..78436239e 100644 --- a/qt/aqt/emptycards.py +++ b/qt/aqt/emptycards.py @@ -63,7 +63,7 @@ class EmptyCardsDialog(QDialog): def on_finished(code: Any) -> None: self.form.webview.cleanup() - self.form.webview = None + self.form.webview = None # type: ignore saveGeom(self, "emptycards") qconnect(self.finished, on_finished) @@ -71,6 +71,7 @@ class EmptyCardsDialog(QDialog): self._delete_button = self.form.buttonBox.addButton( tr.empty_cards_delete_button(), QDialogButtonBox.ButtonRole.ActionRole ) + assert self._delete_button is not None self._delete_button.setAutoDefault(False) qconnect(self._delete_button.clicked, self._on_delete) diff --git a/qt/aqt/flags.py b/qt/aqt/flags.py index 5373206ab..7a1b9aef1 100644 --- a/qt/aqt/flags.py +++ b/qt/aqt/flags.py @@ -34,11 +34,11 @@ class Flag: class FlagManager: def __init__(self, mw: aqt.main.AnkiQt) -> None: self.mw = mw - self._flags: list[Flag] | None = None + self._flags: list[Flag] = [] def all(self) -> list[Flag]: """Return a list of all flags.""" - if self._flags is None: + if not self._flags: self._load_flags() return self._flags @@ -57,7 +57,7 @@ class FlagManager: def require_refresh(self) -> None: "Discard cached labels." - self._flags = None + self._flags = [] def _load_flags(self) -> None: labels = cast(dict[str, str], self.mw.col.get_config("flagLabels", {})) From 763712c69697cbfca6f758ec0602714e2c90c2a8 Mon Sep 17 00:00:00 2001 From: Abdo Date: Sat, 9 Nov 2024 18:42:49 +0300 Subject: [PATCH 077/113] Remove outdated TODO (#3567) --- qt/aqt/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 2936d7969..9482a27e7 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -112,7 +112,6 @@ class MainWebView(AnkiWebView): self.setFocusPolicy(Qt.FocusPolicy.WheelFocus) self.setMinimumWidth(400) self.setAcceptDrops(True) - print("todo: windows paths in import screen") # Importing files via drag & drop ########################################################################## From db7f128b832bc39be1f26bf6a5d40818c2c395cd Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Tue, 12 Nov 2024 08:47:04 -0800 Subject: [PATCH 078/113] Enable strict_optional for aqt/mediacheck, theme, toolbar (#3569) * Enable strict_optional for mediacheck * Fix mypy errors * Enable strict_optional for theme * Fix mypy errors * Enable strict_optional for toolbar * Fix mypy errors --- .mypy.ini | 6 ++++++ qt/aqt/mediacheck.py | 3 +++ qt/aqt/theme.py | 4 +++- qt/aqt/toolbar.py | 6 ++++-- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index da2daea54..729186b0a 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -86,6 +86,12 @@ strict_optional = True strict_optional = True [mypy-aqt.flags] strict_optional = True +[mypy-aqt.mediacheck] +strict_optional = True +[mypy-aqt.theme] +strict_optional = True +[mypy-aqt.toolbar] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/mediacheck.py b/qt/aqt/mediacheck.py index ec47550d8..71ab5a07d 100644 --- a/qt/aqt/mediacheck.py +++ b/qt/aqt/mediacheck.py @@ -80,6 +80,7 @@ class MediaChecker: label = progress.media_check try: + assert self.progress_dialog is not None if self.progress_dialog.wantCancel: self.mw.col.set_wants_abort() except AttributeError: @@ -165,6 +166,7 @@ class MediaChecker: def _on_render_latex(self) -> None: self.progress_dialog = self.mw.progress.start() + assert self.progress_dialog is not None try: out = self.mw.col.media.render_all_latex(self._on_render_latex_progress) if self.progress_dialog.wantCancel: @@ -181,6 +183,7 @@ class MediaChecker: tooltip(tr.media_check_all_latex_rendered()) def _on_render_latex_progress(self, count: int) -> bool: + assert self.progress_dialog is not None if self.progress_dialog.wantCancel: return False diff --git a/qt/aqt/theme.py b/qt/aqt/theme.py index 735f720c4..c43cf8f86 100644 --- a/qt/aqt/theme.py +++ b/qt/aqt/theme.py @@ -231,7 +231,9 @@ class ThemeManager: self._current_widget_style = new_widget_style app = aqt.mw.app if not self._default_style: - self._default_style = app.style().objectName() + style = app.style() + assert style is not None + self._default_style = style.objectName() self._apply_palette(app) self._apply_style(app) gui_hooks.theme_did_change() diff --git a/qt/aqt/toolbar.py b/qt/aqt/toolbar.py index 7313f2a39..2ae8e6d72 100644 --- a/qt/aqt/toolbar.py +++ b/qt/aqt/toolbar.py @@ -37,7 +37,9 @@ class BottomToolbar: class ToolbarWebView(AnkiWebView): hide_condition: Callable[..., bool] - def __init__(self, mw: aqt.AnkiQt, kind: AnkiWebViewKind | None = None) -> None: + def __init__( + self, mw: aqt.AnkiQt, kind: AnkiWebViewKind = AnkiWebViewKind.DEFAULT + ) -> None: AnkiWebView.__init__(self, mw, kind=kind) self.mw = mw self.setFocusPolicy(Qt.FocusPolicy.WheelFocus) @@ -172,7 +174,7 @@ class TopWebView(ToolbarWebView): self.eval("""document.body.style.setProperty("min-height", "0px"); """) self.evalWithCallback("document.documentElement.offsetHeight", self._onHeight) - def resizeEvent(self, event: QResizeEvent) -> None: + def resizeEvent(self, event: QResizeEvent | None) -> None: super().resizeEvent(event) self.mw.web.evalWithCallback( From edf59c2bb2a3dad36115af7518cdcbb3ee397089 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Wed, 13 Nov 2024 01:06:55 -0800 Subject: [PATCH 079/113] Enable strict_optional for aqt/deckchooser, about, webview (#3573) * Enable strict_optional for deckchooser * Fix mypy errors * Enable strict_optional for about * Fix mypy errors * Enable strict_optional for webview * Fix mypy errors * Fix merge error * Revert utils * Add early returns --------- Co-authored-by: Abdo --- .mypy.ini | 6 ++++++ qt/aqt/about.py | 13 ++++++++--- qt/aqt/deckchooser.py | 4 +++- qt/aqt/webview.py | 50 +++++++++++++++++++++++++++++++------------ 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index 729186b0a..e34bccf45 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -92,6 +92,12 @@ strict_optional = True strict_optional = True [mypy-aqt.toolbar] strict_optional = True +[mypy-aqt.deckchooser] +strict_optional = True +[mypy-aqt.about] +strict_optional = True +[mypy-aqt.webview] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/about.py b/qt/aqt/about.py index cf0173592..bf1ff41f8 100644 --- a/qt/aqt/about.py +++ b/qt/aqt/about.py @@ -37,14 +37,21 @@ def show(mw: aqt.AnkiQt) -> QDialog: txt = supportText() if mw.addonManager.dirty: txt += "\n" + addon_debug_info() - QApplication.clipboard().setText(txt) + clipboard = QApplication.clipboard() + assert clipboard is not None + clipboard.setText(txt) tooltip(tr.about_copied_to_clipboard(), parent=dialog) btn = QPushButton(tr.about_copy_debug_info()) qconnect(btn.clicked, on_copy) abt.buttonBox.addButton(btn, QDialogButtonBox.ButtonRole.ActionRole) - abt.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setFocus() + + ok_button = abt.buttonBox.button(QDialogButtonBox.StandardButton.Ok) + assert ok_button is not None + ok_button.setFocus() + btnLayout = abt.buttonBox.layout() + assert btnLayout is not None btnLayout.setContentsMargins(12, 12, 12, 12) # WebView cleanup @@ -52,7 +59,7 @@ def show(mw: aqt.AnkiQt) -> QDialog: def on_dialog_destroyed() -> None: abt.label.cleanup() - abt.label = None + abt.label = None # type: ignore qconnect(dialog.destroyed, on_dialog_destroyed) diff --git a/qt/aqt/deckchooser.py b/qt/aqt/deckchooser.py index 72894ed82..c25fcad1e 100644 --- a/qt/aqt/deckchooser.py +++ b/qt/aqt/deckchooser.py @@ -99,7 +99,9 @@ class DeckChooser(QHBoxLayout): def callback(ret: StudyDeck) -> None: if not ret.name: return - new_selected_deck_id = self.mw.col.decks.by_name(ret.name)["id"] + deck = self.mw.col.decks.by_name(ret.name) + assert deck is not None + new_selected_deck_id = deck["id"] if self.selected_deck_id != new_selected_deck_id: self.selected_deck_id = new_selected_deck_id if func := self.on_deck_changed: diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index 065d5956e..aac3fb1b6 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -89,17 +89,23 @@ class AnkiWebPage(QWebEnginePage): script.setWorldId(QWebEngineScript.ScriptWorldId.MainWorld) script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentReady) script.setRunsOnSubFrames(False) - self.profile().scripts().insert(script) + + profile = self.profile() + assert profile is not None + scripts = profile.scripts() + assert scripts is not None + scripts.insert(script) def javaScriptConsoleMessage( self, level: QWebEnginePage.JavaScriptConsoleMessageLevel, - msg: str, + msg: str | None, line: int, - srcID: str, + srcID: str | None, ) -> None: # not translated because console usually not visible, # and may only accept ascii text + assert srcID is not None if srcID.startswith("data"): srcID = "" else: @@ -162,10 +168,16 @@ class AnkiWebPage(QWebEnginePage): def _onCmd(self, str: str) -> Any: return self._onBridgeCmd(str) - def javaScriptAlert(self, frame: Any, text: str) -> None: + def javaScriptAlert(self, frame: Any, text: str | None) -> None: + if text is None: + return + showInfo(text) - def javaScriptConfirm(self, frame: Any, text: str) -> bool: + def javaScriptConfirm(self, frame: Any, text: str | None) -> bool: + if text is None: + return False + return askUser(text) @@ -328,7 +340,9 @@ class AnkiWebView(QWebEngineView): # with target="_blank") and return view return AnkiWebView() - def eventFilter(self, obj: QObject, evt: QEvent) -> bool: + def eventFilter(self, obj: QObject | None, evt: QEvent | None) -> bool: + if evt is None: + return False if self._disable_zoom and is_gesture_or_zoom_event(evt): return True @@ -377,7 +391,7 @@ class AnkiWebView(QWebEngineView): def onSelectAll(self) -> None: self.triggerPageAction(QWebEnginePage.WebAction.SelectAll) - def contextMenuEvent(self, evt: QContextMenuEvent) -> None: + def contextMenuEvent(self, evt: QContextMenuEvent | None) -> None: m = QMenu(self) self._maybe_add_copy_action(m) gui_hooks.webview_will_show_context_menu(self, m) @@ -387,9 +401,10 @@ class AnkiWebView(QWebEngineView): def _maybe_add_copy_action(self, menu: QMenu) -> None: if self.hasSelection(): a = menu.addAction(tr.actions_copy()) + assert a is not None qconnect(a.triggered, self.onCopy) - def dropEvent(self, evt: QDropEvent) -> None: + def dropEvent(self, evt: QDropEvent | None) -> None: if self.allow_drops: super().dropEvent(evt) @@ -455,7 +470,9 @@ class AnkiWebView(QWebEngineView): return 1 def setPlaybackRequiresGesture(self, value: bool) -> None: - self.settings().setAttribute( + settings = self.settings() + assert settings is not None + settings.setAttribute( QWebEngineSettings.WebAttribute.PlaybackRequiresUserGesture, value ) @@ -632,10 +649,13 @@ html {{ {font} }} def eval(self, js: str) -> None: self.evalWithCallback(js, None) - def evalWithCallback(self, js: str, cb: Callable) -> None: + def evalWithCallback(self, js: str, cb: Callable | None) -> None: self._queueAction("eval", js, cb) - def _evalWithCallback(self, js: str, cb: Callable[[Any], Any]) -> None: + def _evalWithCallback(self, js: str, cb: Callable[[Any], Any] | None) -> None: + page = self.page() + assert page is not None + if cb: def handler(val: Any) -> None: @@ -644,9 +664,9 @@ html {{ {font} }} return cb(val) - self.page().runJavaScript(js, handler) + page.runJavaScript(js, handler) else: - self.page().runJavaScript(js) + page.runJavaScript(js) def _queueAction(self, name: str, *args: Any) -> None: self._pendingActions.append((name, args)) @@ -685,7 +705,9 @@ html {{ {font} }} return if not self._filterSet: - self.focusProxy().installEventFilter(self) + focus_proxy = self.focusProxy() + assert focus_proxy is not None + focus_proxy.installEventFilter(self) self._filterSet = True if cmd == "domDone": From 29f714d9739d6d007b9ce2ba268bf64336550159 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Fri, 15 Nov 2024 05:24:50 -0800 Subject: [PATCH 080/113] Enable strict_optional for aqt/mediasync, package, progress (#3577) * Enable strict_optional for mediasync * Fix mypy errors * Enable strict_optional for package * Fix mypy errors * Enable strict_optional for progress * Fix mypy errors --- .mypy.ini | 6 ++++++ qt/aqt/mediasync.py | 2 +- qt/aqt/package.py | 2 +- qt/aqt/progress.py | 13 ++++++++++--- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index e34bccf45..da56d9d62 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -98,6 +98,12 @@ strict_optional = True strict_optional = True [mypy-aqt.webview] strict_optional = True +[mypy-aqt.mediasync] +strict_optional = True +[mypy-aqt.package] +strict_optional = True +[mypy-aqt.progress] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/qt/aqt/mediasync.py b/qt/aqt/mediasync.py index 96054832c..7cfb6d4a7 100644 --- a/qt/aqt/mediasync.py +++ b/qt/aqt/mediasync.py @@ -119,7 +119,7 @@ class MediaSyncer: diag: MediaSyncDialog = aqt.dialogs.open("sync_log", self.mw, self, True) diag.show() - timer: QTimer | None = None + timer: QTimer def check_finished() -> None: if not self.is_syncing(): diff --git a/qt/aqt/package.py b/qt/aqt/package.py index 3f89366a2..f1ee8cd79 100644 --- a/qt/aqt/package.py +++ b/qt/aqt/package.py @@ -41,7 +41,7 @@ def _patch_pkgutil() -> None: def get_data_custom(package: str, resource: str) -> bytes | None: try: module = importlib.import_module(package) - reader = module.__loader__.get_resource_reader(package) # type: ignore[attr-defined] + reader = module.__loader__.get_resource_reader(package) # type: ignore with reader.open_resource(resource) as f: return f.read() except Exception: diff --git a/qt/aqt/progress.py b/qt/aqt/progress.py index 84d23a22e..4d23b33f4 100644 --- a/qt/aqt/progress.py +++ b/qt/aqt/progress.py @@ -216,6 +216,8 @@ class ProgressManager: self._maybeShow() if not self._shown: return + + assert self._win is not None if label: self._win.form.label.setText(label) @@ -290,6 +292,7 @@ class ProgressManager: self._showWin() def _showWin(self) -> None: + assert self._win is not None self._shown = time.monotonic() self._win.show() @@ -297,6 +300,7 @@ class ProgressManager: # if the parent window has been deleted, the progress dialog may have # already been dropped; delete it if it hasn't been if not sip.isdeleted(self._win): + assert self._win is not None self._win.cancel() self._win = None self._shown = 0 @@ -314,6 +318,7 @@ class ProgressManager: def _on_show_timer(self) -> None: if self.mw.app.focusWindow() is None: # if no window is focused (eg app is minimized), defer display + assert self._show_timer is not None self._show_timer.start(10) return @@ -334,7 +339,7 @@ class ProgressManager: class ProgressDialog(QDialog): - def __init__(self, parent: QWidget) -> None: + def __init__(self, parent: QWidget | None) -> None: QDialog.__init__(self, parent) disable_help_button(self) self.form = aqt.forms.progress.Ui_Dialog() @@ -349,14 +354,16 @@ class ProgressDialog(QDialog): self.hide() self.deleteLater() - def closeEvent(self, evt: QCloseEvent) -> None: + def closeEvent(self, evt: QCloseEvent | None) -> None: + assert evt is not None if self._closingDown: evt.accept() else: self.wantCancel = True evt.ignore() - def keyPressEvent(self, evt: QKeyEvent) -> None: + def keyPressEvent(self, evt: QKeyEvent | None) -> None: + assert evt is not None if evt.key() == Qt.Key.Key_Escape: evt.ignore() self.wantCancel = True From 9d09c32ecebc13b9e4f4dfb671feac51ddefcd74 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Fri, 15 Nov 2024 05:29:19 -0800 Subject: [PATCH 081/113] Enable strict_optional for aqt/tagedit, utils, sync (#3578) * Enable strict_optional for tagedit * Fix mypy errors * Enable strict_optional for utils * Fix mypy errors * Enable strict_optional for sync * Fix mypy errors --------- Co-authored-by: Abdo --- .mypy.ini | 6 +++ pylib/anki/collection.py | 2 +- qt/aqt/stats.py | 4 +- qt/aqt/sync.py | 10 ++-- qt/aqt/tagedit.py | 37 ++++++++------ qt/aqt/utils.py | 101 ++++++++++++++++++++++++++++----------- 6 files changed, 111 insertions(+), 49 deletions(-) diff --git a/.mypy.ini b/.mypy.ini index da56d9d62..648c6a6ea 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -104,6 +104,12 @@ strict_optional = True strict_optional = True [mypy-aqt.progress] strict_optional = True +[mypy-aqt.tagedit] +strict_optional = True +[mypy-aqt.utils] +strict_optional = True +[mypy-aqt.sync] +strict_optional = True [mypy-anki.scheduler.base] strict_optional = True [mypy-anki._backend.rsbridge] diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index 208ed6448..43e443eef 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -1128,7 +1128,7 @@ class Collection(DeprecatedNamesMixin): self._backend.abort_sync() def full_upload_or_download( - self, *, auth: SyncAuth, server_usn: int | None, upload: bool + self, *, auth: SyncAuth | None, server_usn: int | None, upload: bool ) -> None: self._backend.full_upload_or_download( sync_pb2.FullUploadOrDownloadRequest( diff --git a/qt/aqt/stats.py b/qt/aqt/stats.py index 05caf97f2..7842b27a9 100644 --- a/qt/aqt/stats.py +++ b/qt/aqt/stats.py @@ -94,7 +94,7 @@ class NewDeckStats(QDialog): lambda _: self.refresh() ).run_in_background() - def _imagePath(self) -> str: + def _imagePath(self) -> str | None: name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time())) name = f"anki-{tr.statistics_stats()}{name}" file = getSaveFile( @@ -196,7 +196,7 @@ class DeckStats(QDialog): self.reject() callback() - def _imagePath(self) -> str: + def _imagePath(self) -> str | None: name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time())) name = f"anki-{tr.statistics_stats()}{name}" file = getSaveFile( diff --git a/qt/aqt/sync.py b/qt/aqt/sync.py index cea64fadc..2b8bd59af 100644 --- a/qt/aqt/sync.py +++ b/qt/aqt/sync.py @@ -168,7 +168,7 @@ def full_sync( def confirm_full_download( - mw: aqt.main.AnkiQt, server_usn: int, on_done: Callable[[], None] + mw: aqt.main.AnkiQt, server_usn: int | None, on_done: Callable[[], None] ) -> None: # confirmation step required, as some users customize their notetypes # in an empty collection, then want to upload them @@ -184,7 +184,7 @@ def confirm_full_download( def confirm_full_upload( - mw: aqt.main.AnkiQt, server_usn: int, on_done: Callable[[], None] + mw: aqt.main.AnkiQt, server_usn: int | None, on_done: Callable[[], None] ) -> None: # confirmation step required, as some users have reported an upload # happening despite having their AnkiWeb collection not being empty @@ -220,7 +220,7 @@ def on_full_sync_timer(mw: aqt.main.AnkiQt, label: str) -> None: def full_download( - mw: aqt.main.AnkiQt, server_usn: int, on_done: Callable[[], None] + mw: aqt.main.AnkiQt, server_usn: int | None, on_done: Callable[[], None] ) -> None: label = tr.sync_downloading_from_ankiweb() @@ -372,7 +372,9 @@ def get_id_and_pass_from_user( l2.setBuddy(passwd) vbox.addLayout(g) bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) # type: ignore - bb.button(QDialogButtonBox.StandardButton.Ok).setAutoDefault(True) + ok_button = bb.button(QDialogButtonBox.StandardButton.Ok) + assert ok_button is not None + ok_button.setAutoDefault(True) qconnect(bb.accepted, diag.accept) qconnect(bb.rejected, diag.reject) vbox.addWidget(bb) diff --git a/qt/aqt/tagedit.py b/qt/aqt/tagedit.py index 5c9686210..d85d6655a 100644 --- a/qt/aqt/tagedit.py +++ b/qt/aqt/tagedit.py @@ -42,13 +42,17 @@ class TagEdit(QLineEdit): l = (d.name for d in self.col.decks.all_names_and_ids()) self.model.setStringList(l) - def focusInEvent(self, evt: QFocusEvent) -> None: + def focusInEvent(self, evt: QFocusEvent | None) -> None: QLineEdit.focusInEvent(self, evt) - def keyPressEvent(self, evt: QKeyEvent) -> None: + def keyPressEvent(self, evt: QKeyEvent | None) -> None: + assert evt is not None + popup = self._completer.popup() + assert popup is not None + if evt.key() in (Qt.Key.Key_Up, Qt.Key.Key_Down): # show completer on arrow key up/down - if not self._completer.popup().isVisible(): + if not popup.isVisible(): self.showCompleter() return if ( @@ -56,24 +60,21 @@ class TagEdit(QLineEdit): and evt.modifiers() & Qt.KeyboardModifier.ControlModifier ): # select next completion - if not self._completer.popup().isVisible(): + if not popup.isVisible(): self.showCompleter() index = self._completer.currentIndex() - self._completer.popup().setCurrentIndex(index) + popup.setCurrentIndex(index) cur_row = index.row() if not self._completer.setCurrentRow(cur_row + 1): self._completer.setCurrentRow(0) return - if ( - evt.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return) - and self._completer.popup().isVisible() - ): + if evt.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return) and popup.isVisible(): # apply first completion if no suggestion selected - selected_row = self._completer.popup().currentIndex().row() + selected_row = popup.currentIndex().row() if selected_row == -1: self._completer.setCurrentRow(0) index = self._completer.currentIndex() - self._completer.popup().setCurrentIndex(index) + popup.setCurrentIndex(index) self.hideCompleter() QWidget.keyPressEvent(self, evt) return @@ -97,15 +98,19 @@ class TagEdit(QLineEdit): self._completer.setCompletionPrefix(self.text()) self._completer.complete() - def focusOutEvent(self, evt: QFocusEvent) -> None: + def focusOutEvent(self, evt: QFocusEvent | None) -> None: QLineEdit.focusOutEvent(self, evt) self.lostFocus.emit() # type: ignore - self._completer.popup().hide() + popup = self._completer.popup() + assert popup is not None + popup.hide() def hideCompleter(self) -> None: if sip.isdeleted(self._completer): # type: ignore return - self._completer.popup().hide() + popup = self._completer.popup() + assert popup is not None + popup.hide() class TagCompleter(QCompleter): @@ -120,7 +125,9 @@ class TagCompleter(QCompleter): self.edit = edit self.cursor: int | None = None - def splitPath(self, tags: str) -> list[str]: + def splitPath(self, tags: str | None) -> list[str]: + assert tags is not None + assert self.edit.col is not None stripped_tags = tags.strip() stripped_tags = re.sub(" +", " ", stripped_tags) self.tags = self.edit.col.tags.split(stripped_tags) diff --git a/qt/aqt/utils.py b/qt/aqt/utils.py index ac11694e1..23266ebaf 100644 --- a/qt/aqt/utils.py +++ b/qt/aqt/utils.py @@ -118,10 +118,13 @@ HelpPageArgument = Union["HelpPage.V", str] def openHelp(section: HelpPageArgument) -> None: + assert tr.backend is not None + backend = tr.backend() + assert backend is not None if isinstance(section, str): - link = tr.backend().help_page_link(page=HelpPage.INDEX) + section + link = backend.help_page_link(page=HelpPage.INDEX) + section else: - link = tr.backend().help_page_link(page=section) + link = backend.help_page_link(page=section) openLink(link) @@ -170,17 +173,20 @@ class MessageBox(QMessageBox): b = self.addButton(button) # a translator has complained the default Qt translation is inappropriate, so we override it if button == QMessageBox.StandardButton.Discard: + assert b is not None b.setText(tr.actions_discard()) elif isinstance(button, tuple): b = self.addButton(button[0], button[1]) else: continue if callback is not None: + assert b is not None qconnect(b.clicked, partial(callback, i)) if i == default_button: self.setDefaultButton(b) if help is not None: b = self.addButton(QMessageBox.StandardButton.Help) + assert b is not None qconnect(b.clicked, lambda: openHelp(help)) self.open() @@ -316,9 +322,11 @@ def showInfo( mb.setDefaultButton(default) else: b = mb.addButton(QMessageBox.StandardButton.Ok) + assert b is not None b.setDefault(True) if help is not None: b = mb.addButton(QMessageBox.StandardButton.Help) + assert b is not None qconnect(b.clicked, lambda: openHelp(help)) b.setAutoDefault(False) return mb.exec() @@ -363,7 +371,9 @@ def showText( if copyBtn: def onCopy() -> None: - QApplication.clipboard().setText(text.toPlainText()) + clipboard = QApplication.clipboard() + assert clipboard is not None + clipboard.setText(text.toPlainText()) btn = QPushButton(tr.qt_misc_copy_to_clipboard()) qconnect(btn.clicked, onCopy) @@ -415,6 +425,7 @@ def askUser( default = QMessageBox.StandardButton.Yes r = msgfunc(parent, title, text, sb, default) if r == QMessageBox.StandardButton.Help: + assert help is not None openHelp(help) else: break @@ -431,7 +442,7 @@ class ButtonedDialog(QMessageBox): title: str = "Anki", ): QMessageBox.__init__(self, parent) - self._buttons: list[QPushButton] = [] + self._buttons: list[QPushButton | None] = [] self.setWindowTitle(title) self.help = help self.setIcon(QMessageBox.Icon.Warning) @@ -444,11 +455,13 @@ class ButtonedDialog(QMessageBox): def run(self) -> str: self.exec() - but = self.clickedButton().text() - if but == "Help": + clicked_button = self.clickedButton() + assert clicked_button is not None + txt = clicked_button.text() + if txt == "Help": # FIXME stop dialog closing? + assert self.help is not None openHelp(self.help) - txt = self.clickedButton().text() # work around KDE 'helpfully' adding accelerators to button text of Qt apps return txt.replace("&", "") @@ -504,13 +517,18 @@ class GetTextDialog(QDialog): b = QDialogButtonBox(buts) # type: ignore v.addWidget(b) self.setLayout(v) - qconnect(b.button(QDialogButtonBox.StandardButton.Ok).clicked, self.accept) - qconnect(b.button(QDialogButtonBox.StandardButton.Cancel).clicked, self.reject) + ok_button = b.button(QDialogButtonBox.StandardButton.Ok) + assert ok_button is not None + qconnect(ok_button.clicked, self.accept) + + cancel_button = b.button(QDialogButtonBox.StandardButton.Cancel) + assert cancel_button is not None + qconnect(cancel_button.clicked, self.reject) + if help: - qconnect( - b.button(QDialogButtonBox.StandardButton.Help).clicked, - self.helpRequested, - ) + help_button = b.button(QDialogButtonBox.StandardButton.Help) + assert help_button is not None + qconnect(help_button.clicked, self.helpRequested) self.l.setFocus() def accept(self) -> None: @@ -520,7 +538,8 @@ class GetTextDialog(QDialog): return QDialog.reject(self) def helpRequested(self) -> None: - openHelp(self.help) + if self.help is not None: + openHelp(self.help) def getText( @@ -624,6 +643,7 @@ def getFile( if dir and key: raise Exception("expected dir or key") if not dir: + assert aqt.mw.pm.profile is not None dirkey = f"{key}Directory" dir = aqt.mw.pm.profile.get(dirkey, "") else: @@ -635,6 +655,7 @@ def getFile( else QFileDialog.FileMode.ExistingFile ) d.setFileMode(mode) + assert dir is not None if os.path.exists(dir): d.setDirectory(dir) d.setWindowTitle(title) @@ -644,6 +665,7 @@ def getFile( def accept() -> None: files = list(d.selectedFiles()) if dirkey: + assert aqt.mw.pm.profile is not None dir = os.path.dirname(files[0]) aqt.mw.pm.profile[dirkey] = dir result = files if multi else files[0] @@ -683,10 +705,11 @@ def getSaveFile( dir_description: str, key: str, ext: str, - fname: str | None = None, -) -> str: + fname: str = "", +) -> str | None: """Ask the user for a file to save. Use DIR_DESCRIPTION as config variable. The file dialog will default to open with FNAME.""" + assert aqt.mw.pm.profile is not None config_key = f"{dir_description}Directory" defaultPath = QStandardPaths.writableLocation( @@ -709,9 +732,10 @@ def getSaveFile( dir = os.path.dirname(file) aqt.mw.pm.profile[config_key] = dir # check if it exists - if os.path.exists(file): - if not askUser(tr.qt_misc_this_file_exists_are_you_sure(), parent): - return None + if os.path.exists(file) and not askUser( + tr.qt_misc_this_file_exists_are_you_sure(), parent + ): + return None return file @@ -735,6 +759,7 @@ def _qt_state_key(kind: _QtStateKeyKind, key: str) -> str: def saveGeom(widget: QWidget, key: str) -> None: # restoring a fullscreen window breaks the tab functionality of 5.15 if not widget.isFullScreen() or qtmajor == 6: + assert aqt.mw.pm.profile is not None key = _qt_state_key(_QtStateKeyKind.GEOMETRY, key) aqt.mw.pm.profile[key] = widget.saveGeometry() @@ -745,6 +770,7 @@ def restoreGeom( adjustSize: bool = False, default_size: tuple[int, int] | None = None, ) -> None: + assert aqt.mw.pm.profile is not None key = _qt_state_key(_QtStateKeyKind.GEOMETRY, key) if existing_geom := aqt.mw.pm.profile.get(key): widget.restoreGeometry(existing_geom) @@ -756,7 +782,9 @@ def restoreGeom( def ensureWidgetInScreenBoundaries(widget: QWidget) -> None: - handle = widget.window().windowHandle() + window = widget.window() + assert window is not None + handle = window.windowHandle() if not handle: # window has not yet been shown, retry later aqt.mw.progress.timer( @@ -765,7 +793,9 @@ def ensureWidgetInScreenBoundaries(widget: QWidget) -> None: return # ensure widget is smaller than screen bounds - geom = handle.screen().availableGeometry() + screen = handle.screen() + assert screen is not None + geom = screen.availableGeometry() wsize = widget.size() cappedWidth = min(geom.width(), wsize.width()) cappedHeight = min(geom.height(), wsize.height()) @@ -784,44 +814,52 @@ def ensureWidgetInScreenBoundaries(widget: QWidget) -> None: def saveState(widget: QFileDialog | QMainWindow, key: str) -> None: + assert aqt.mw.pm.profile is not None key = _qt_state_key(_QtStateKeyKind.STATE, key) aqt.mw.pm.profile[key] = widget.saveState() def restoreState(widget: QFileDialog | QMainWindow, key: str) -> None: + assert aqt.mw.pm.profile is not None key = _qt_state_key(_QtStateKeyKind.STATE, key) if data := aqt.mw.pm.profile.get(key): widget.restoreState(data) def saveSplitter(widget: QSplitter, key: str) -> None: + assert aqt.mw.pm.profile is not None key = _qt_state_key(_QtStateKeyKind.SPLITTER, key) aqt.mw.pm.profile[key] = widget.saveState() def restoreSplitter(widget: QSplitter, key: str) -> None: + assert aqt.mw.pm.profile is not None key = _qt_state_key(_QtStateKeyKind.SPLITTER, key) if data := aqt.mw.pm.profile.get(key): widget.restoreState(data) def saveHeader(widget: QHeaderView, key: str) -> None: + assert aqt.mw.pm.profile is not None key = _qt_state_key(_QtStateKeyKind.HEADER, key) aqt.mw.pm.profile[key] = widget.saveState() def restoreHeader(widget: QHeaderView, key: str) -> None: + assert aqt.mw.pm.profile is not None key = _qt_state_key(_QtStateKeyKind.HEADER, key) if state := aqt.mw.pm.profile.get(key): widget.restoreState(state) def save_is_checked(widget: QCheckBox, key: str) -> None: + assert aqt.mw.pm.profile is not None key += "IsChecked" aqt.mw.pm.profile[key] = widget.isChecked() def restore_is_checked(widget: QCheckBox, key: str) -> None: + assert aqt.mw.pm.profile is not None key += "IsChecked" if aqt.mw.pm.profile.get(key) is not None: widget.setChecked(aqt.mw.pm.profile[key]) @@ -847,8 +885,11 @@ def restore_combo_index_for_session( def save_combo_history(comboBox: QComboBox, history: list[str], name: str) -> str: + assert aqt.mw.pm.profile is not None name += "BoxHistory" - text_input = comboBox.lineEdit().text() + line_edit = comboBox.lineEdit() + assert line_edit is not None + text_input = line_edit.text() if text_input in history: history.remove(text_input) history.insert(0, text_input) @@ -861,14 +902,17 @@ def save_combo_history(comboBox: QComboBox, history: list[str], name: str) -> st def restore_combo_history(comboBox: QComboBox, name: str) -> list[str]: + assert aqt.mw.pm.profile is not None name += "BoxHistory" history = aqt.mw.pm.profile.get(name, []) comboBox.addItems([""] + history) if history: session_input = aqt.mw.pm.session.get(name) if session_input and session_input == history[0]: - comboBox.lineEdit().setText(session_input) - comboBox.lineEdit().selectAll() + line_edit = comboBox.lineEdit() + assert line_edit is not None + line_edit.setText(session_input) + line_edit.selectAll() return history @@ -980,7 +1024,7 @@ def send_to_trash(path: Path) -> None: except Exception as exc: # Linux users may not have a trash folder set up print("trash failure:", path, exc) - if path.is_dir: + if path.is_dir(): shutil.rmtree(path) else: path.unlink() @@ -1005,7 +1049,8 @@ def tooltip( class CustomLabel(QLabel): silentlyClose = True - def mousePressEvent(self, evt: QMouseEvent) -> None: + def mousePressEvent(self, evt: QMouseEvent | None) -> None: + assert evt is not None evt.accept() self.hide() @@ -1074,7 +1119,7 @@ class MenuList: print( "MenuList will be removed; please copy it into your add-on's code if you need it." ) - self.children: list[MenuListChild] = [] + self.children: list[MenuListChild | None] = [] def addItem(self, title: str, func: Callable) -> MenuItem: item = MenuItem(title, func) @@ -1114,6 +1159,7 @@ class SubMenu(MenuList): def renderTo(self, menu: QMenu) -> None: submenu = menu.addMenu(self.title) + assert submenu is not None super().renderTo(submenu) @@ -1124,6 +1170,7 @@ class MenuItem: def renderTo(self, qmenu: QMenu) -> None: a = qmenu.addAction(self.title) + assert a is not None qconnect(a.triggered, self.func) From 15b48cf894b6c258b0a08b9e7a37bb47aba447dd Mon Sep 17 00:00:00 2001 From: user1823 <92206575+user1823@users.noreply.github.com> Date: Sun, 17 Nov 2024 15:38:01 +0530 Subject: [PATCH 082/113] Correct a comment (#3570) Because of the `entry.button_chosen == 0` part, it also filters out reschedule entries. Frankly, we don't need the `(entry.review_kind == RevlogReviewKind::Rescheduled)` part, but I didn't remove it yet. Co-authored-by: Abdo --- rslib/src/scheduler/fsrs/params.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rslib/src/scheduler/fsrs/params.rs b/rslib/src/scheduler/fsrs/params.rs index d31e2aa86..bea1f5e82 100644 --- a/rslib/src/scheduler/fsrs/params.rs +++ b/rslib/src/scheduler/fsrs/params.rs @@ -343,7 +343,7 @@ pub(crate) fn single_card_revlog_to_items( // Filter out unwanted entries entries.retain(|entry| { !( - // set due date or reset + // set due date, reset or rescheduled (entry.review_kind == RevlogReviewKind::Manual || entry.button_chosen == 0) || // cram (entry.review_kind == RevlogReviewKind::Filtered && entry.ease_factor == 0) From d3f2f45805bf7ed07eff5c27bfd1d94e36a62393 Mon Sep 17 00:00:00 2001 From: sorata <136738526+brishtibheja@users.noreply.github.com> Date: Sun, 17 Nov 2024 20:07:21 +0530 Subject: [PATCH 083/113] update links (#3562) --- rslib/src/template.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rslib/src/template.rs b/rslib/src/template.rs index 4ae93e4f8..d5579310d 100644 --- a/rslib/src/template.rs +++ b/rslib/src/template.rs @@ -33,7 +33,7 @@ static TEMPLATE_ERROR_LINK: &str = static TEMPLATE_BLANK_LINK: &str = "https://docs.ankiweb.net/templates/errors.html#front-of-card-is-blank"; static TEMPLATE_BLANK_CLOZE_LINK: &str = - "https://docs.ankiweb.net/templates/errors.html#no-cloze-filter-on-cloze-notetype"; + "https://docs.ankiweb.net/templates/errors.html#no-cloze-filter-on-cloze-note-type"; // Lexing //---------------------------------------- From 03c50c8332850af2260ebd828801f7992c2a0972 Mon Sep 17 00:00:00 2001 From: Abdo Date: Sun, 17 Nov 2024 17:38:21 +0300 Subject: [PATCH 084/113] Do not show warning if Browser Appearance has no field references (#3566) --- rslib/src/template.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rslib/src/template.rs b/rslib/src/template.rs index d5579310d..b72831851 100644 --- a/rslib/src/template.rs +++ b/rslib/src/template.rs @@ -628,7 +628,7 @@ pub fn render_card( TEMPLATE_BLANK_CLOZE_LINK, tr.card_template_rendering_more_info() )) - } else if !is_cloze && !qtmpl.renders_with_fields(context.nonempty_fields) { + } else if !is_cloze && !browser && !qtmpl.renders_with_fields(context.nonempty_fields) { Some(format!( "
{}
{}
", tr.card_template_rendering_empty_front(), From b933796a5155738cde49f55b63265ac8e8f7f8f2 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Sun, 17 Nov 2024 15:39:13 +0100 Subject: [PATCH 085/113] Fix setting tags column to first unmapped column (#3568) Closes #3561. --- rslib/src/import_export/text/csv/metadata.rs | 23 ++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/rslib/src/import_export/text/csv/metadata.rs b/rslib/src/import_export/text/csv/metadata.rs index 17db20eae..0c624958e 100644 --- a/rslib/src/import_export/text/csv/metadata.rs +++ b/rslib/src/import_export/text/csv/metadata.rs @@ -497,9 +497,9 @@ fn maybe_set_tags_column(metadata: &mut CsvMetadata, meta_columns: &HashSet Date: Sun, 17 Nov 2024 18:11:21 +0300 Subject: [PATCH 086/113] Fix editor width changing as tag completions shown (#3574) * Fix editor width changing as tag completions shown * Avoid @render for now * Ignore eslint warning --- ts/lib/components/Portal.svelte | 45 +++++++++++++++++++++++ ts/lib/components/RenderChildren.svelte | 6 +++ ts/lib/components/WithFloating.svelte | 22 ++++++----- ts/lib/sveltelib/portal.ts | 36 ------------------ ts/lib/tag-editor/WithAutocomplete.svelte | 1 + 5 files changed, 64 insertions(+), 46 deletions(-) create mode 100644 ts/lib/components/Portal.svelte create mode 100644 ts/lib/components/RenderChildren.svelte delete mode 100644 ts/lib/sveltelib/portal.ts diff --git a/ts/lib/components/Portal.svelte b/ts/lib/components/Portal.svelte new file mode 100644 index 000000000..a71788ae2 --- /dev/null +++ b/ts/lib/components/Portal.svelte @@ -0,0 +1,45 @@ + + + + + + +{#if !target} + + + +{/if} diff --git a/ts/lib/components/RenderChildren.svelte b/ts/lib/components/RenderChildren.svelte new file mode 100644 index 000000000..e09533eae --- /dev/null +++ b/ts/lib/components/RenderChildren.svelte @@ -0,0 +1,6 @@ + + + diff --git a/ts/lib/components/WithFloating.svelte b/ts/lib/components/WithFloating.svelte index 418054793..b8e19ef35 100644 --- a/ts/lib/components/WithFloating.svelte +++ b/ts/lib/components/WithFloating.svelte @@ -19,7 +19,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import type { EventPredicateResult } from "$lib/sveltelib/event-predicate"; import { documentClick, documentKeyup } from "$lib/sveltelib/event-store"; import { registerModalClosingHandler } from "$lib/sveltelib/modal-closing"; - import portal from "$lib/sveltelib/portal"; + import Portal from "./Portal.svelte"; import type { PositioningCallback } from "$lib/sveltelib/position/auto-update"; import autoUpdate from "$lib/sveltelib/position/auto-update"; import type { PositionAlgorithm } from "$lib/sveltelib/position/position-algorithm"; @@ -195,17 +195,19 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html {/if} {/if} -
- {#if show} - - {/if} - - + From f345517dcc8e7785b70fcd3de21fd69a407535c7 Mon Sep 17 00:00:00 2001 From: user1823 <92206575+user1823@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:07:43 +0530 Subject: [PATCH 105/113] Change font of debug console to Consolas (#3606) --- qt/aqt/debug_console.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qt/aqt/debug_console.py b/qt/aqt/debug_console.py index 2ad9843db..d709b25e2 100644 --- a/qt/aqt/debug_console.py +++ b/qt/aqt/debug_console.py @@ -72,8 +72,10 @@ class DebugConsole(QDialog): qconnect(self._script.currentIndexChanged, self._on_script_change) def _setup_text_edits(self): - font = QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont) - font.setPointSize(self._text.font().pointSize() + 1) + font = QFont("Consolas") + if not font.exactMatch(): + font = QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont) + font.setPointSize(self._text.font().pointSize()) self._text.setFont(font) self._log.setFont(font) From a4626bf48e0264df9425ce5fe52ddda367693517 Mon Sep 17 00:00:00 2001 From: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Date: Fri, 6 Dec 2024 05:41:34 -0800 Subject: [PATCH 106/113] Remove infinite spinning icon for reset parameters dropdown and add a question mark (#3603) * Add question mark to popup words * Remove spinning icon * Formatting --- ftl/core/deck-config.ftl | 2 +- ts/lib/components/RevertButton.svelte | 27 ++------------------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/ftl/core/deck-config.ftl b/ftl/core/deck-config.ftl index 5f373c990..c726cb5d1 100644 --- a/ftl/core/deck-config.ftl +++ b/ftl/core/deck-config.ftl @@ -315,7 +315,7 @@ deck-config-confirm-remove-name = Remove { $name }? deck-config-save-button = Save deck-config-save-to-all-subdecks = Save to All Subdecks deck-config-save-and-optimize = Optimize All Presets -deck-config-revert-button-tooltip = Restore this setting to its default value. +deck-config-revert-button-tooltip = Restore this setting to its default value? ## These strings are shown via the Description button at the bottom of the ## overview screen. diff --git a/ts/lib/components/RevertButton.svelte b/ts/lib/components/RevertButton.svelte index b62bb53ad..a1d6af06d 100644 --- a/ts/lib/components/RevertButton.svelte +++ b/ts/lib/components/RevertButton.svelte @@ -5,12 +5,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html @@ -31,7 +32,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html {/if} {#if fsrsEnabled} - + {/if} {:else} diff --git a/ts/routes/card-info/ForgettingCurve.svelte b/ts/routes/card-info/ForgettingCurve.svelte index 227d2c108..b3fffc16a 100644 --- a/ts/routes/card-info/ForgettingCurve.svelte +++ b/ts/routes/card-info/ForgettingCurve.svelte @@ -20,6 +20,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import HoverColumns from "../graphs/HoverColumns.svelte"; export let revlog: RevlogEntry[]; + export let desiredRetention: number; let svg = null as HTMLElement | SVGElement | null; const bounds = defaultGraphBounds(); const title = tr.cardStatsFsrsForgettingCurveTitle(); @@ -35,7 +36,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } const timeRange = writable(defaultTimeRange); - $: renderForgettingCurve(filteredRevlog, $timeRange, svg as SVGElement, bounds); + $: renderForgettingCurve( + filteredRevlog, + $timeRange, + svg as SVGElement, + bounds, + desiredRetention, + );
diff --git a/ts/routes/card-info/forgetting-curve.ts b/ts/routes/card-info/forgetting-curve.ts index 66d4ebb4f..b5c71b761 100644 --- a/ts/routes/card-info/forgetting-curve.ts +++ b/ts/routes/card-info/forgetting-curve.ts @@ -161,6 +161,7 @@ export function renderForgettingCurve( timeRange: TimeRange, svgElem: SVGElement, bounds: GraphBounds, + desiredRetention: number, ) { const svg = select(svgElem); const trans = svg.transition().duration(600) as any; @@ -204,18 +205,63 @@ export function renderForgettingCurve( .call((selection) => selection.transition(trans).call(axisLeft(y).tickSizeOuter(0))) .attr("direction", "ltr"); + svg.select(".y-ticks .y-axis-title").remove(); + svg.select(".y-ticks") + .append("text") + .attr("class", "y-axis-title") + .attr("transform", "rotate(-90)") + .attr("y", 0 - bounds.marginLeft) + .attr("x", 0 - (bounds.height / 2)) + .attr("font-size", "1rem") + .attr("dy", "1.1em") + .attr("fill", "currentColor") + .style("text-anchor", "middle") + .text(`${tr.cardStatsFsrsForgettingCurveProbabilityOfRecalling()}(%)`); + const lineGenerator = line() .x((d) => x(d.date)) .y((d) => y(d.retrievability)); + // gradient color + const desiredRetentionY = desiredRetention * 100; + svg.append("linearGradient") + .attr("id", "line-gradient") + .attr("gradientUnits", "userSpaceOnUse") + .attr("x1", 0) + .attr("y1", y(0)) + .attr("x2", 0) + .attr("y2", y(100)) + .selectAll("stop") + .data([ + { offset: "0%", color: "tomato" }, + { offset: `${desiredRetentionY}%`, color: "steelblue" }, + { offset: "100%", color: "green" }, + ]) + .enter().append("stop") + .attr("offset", d => d.offset) + .attr("stop-color", d => d.color); + svg.append("path") .datum(data) .attr("class", "forgetting-curve-line") .attr("fill", "none") - .attr("stroke", "steelblue") + .attr("stroke", "url(#line-gradient)") .attr("stroke-width", 1.5) .attr("d", lineGenerator); + svg.select(".desired-retention-line").remove(); + if (desiredRetentionY > yMin) { + svg.append("line") + .attr("class", "desired-retention-line") + .attr("x1", bounds.marginLeft) + .attr("x2", bounds.width - bounds.marginRight) + .attr("y1", y(desiredRetentionY)) + .attr("y2", y(desiredRetentionY)) + .attr("stroke", "steelblue") + .attr("stroke-dasharray", "4 4") + .attr("stroke-width", 1.2); + } + const focusLine = svg.append("line") .attr("class", "focus-line") .attr("y1", bounds.marginTop) @@ -248,11 +294,18 @@ export function renderForgettingCurve( .attr("fill", "transparent") .on("mousemove", (event: MouseEvent, d: DataPoint) => { const [x1, y1] = pointer(event, document.body); + const [_, y2] = pointer(event, svg.node()); + + const lineY = y(desiredRetentionY); focusLine.attr("x1", x(d.date) - 1).attr("x2", x(d.date) + 1).style( "opacity", 1, ); - showTooltip(tooltipText(d), x1, y1); + let text = tooltipText(d); + if (y2 >= lineY - 10 && y2 <= lineY + 10) { + text += `
${tr.cardStatsFsrsForgettingCurveDesiredRetention()}: ${desiredRetention.toFixed(2)}`; + } + showTooltip(text, x1, y1); }) .on("mouseout", () => { focusLine.style("opacity", 0); From 9c3f89466d38d72daf8f671d6f3c8b18351bc642 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 9 Dec 2024 19:40:16 +1100 Subject: [PATCH 113/113] Fix glibc tag for AMD build --- build/configure/src/python.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/configure/src/python.rs b/build/configure/src/python.rs index 02f064b5c..ba304de2a 100644 --- a/build/configure/src/python.rs +++ b/build/configure/src/python.rs @@ -142,7 +142,7 @@ impl BuildAction for BuildWheel { let tag = if let Some(platform) = self.platform { let platform = match platform { - Platform::LinuxX64 => "manylinux_2_28_x86_64", + Platform::LinuxX64 => "manylinux_2_31_x86_64", Platform::LinuxArm => "manylinux_2_31_aarch64", Platform::MacX64 => "macosx_10_13_x86_64", Platform::MacArm => "macosx_11_0_arm64",