diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 7119afd3..24e80dc4 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -106,6 +106,7 @@ gethostname = "0.5.0" humantime = "2.1.0" itertools = "0.13.0" quick_cache = "0.6.2" +safe-transmute = "0.11.3" shell-words = "1.1.0" strum = { version = "0.26.3", features = ["derive"] } zstd = "0.13.2" diff --git a/crates/core/src/commands/check.rs b/crates/core/src/commands/check.rs index d22c3af3..f783ca77 100644 --- a/crates/core/src/commands/check.rs +++ b/crates/core/src/commands/check.rs @@ -1,18 +1,23 @@ //! `check` subcommand -use std::collections::HashMap; +use std::{ + collections::{BTreeSet, HashMap}, + str::FromStr, +}; use bytes::Bytes; +use bytesize::ByteSize; use derive_setters::Setters; -use itertools::Itertools; use log::{debug, error, warn}; -use rayon::prelude::{IntoParallelIterator, ParallelBridge, ParallelIterator}; +use rand::{prelude::SliceRandom, thread_rng, Rng}; +use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use zstd::stream::decode_all; use crate::{ backend::{cache::Cache, decrypt::DecryptReadBackend, node::NodeType, FileType, ReadBackend}, blob::{tree::TreeStreamerOnce, BlobId, BlobType}, crypto::hasher::hash, - error::{RusticErrorKind, RusticResult}, + error::{CommandErrorKind, RusticErrorKind, RusticResult}, + id::Id, index::{ binarysorted::{IndexCollector, IndexType}, GlobalIndex, ReadGlobalIndex, @@ -20,11 +25,98 @@ use crate::{ progress::{Progress, ProgressBars}, repofile::{ packfile::PackId, IndexFile, IndexPack, PackHeader, PackHeaderLength, PackHeaderRef, - SnapshotFile, }, repository::{Open, Repository}, + TreeId, }; +#[derive(Clone, Copy, Debug, Default)] +/// Options to specify which subset of packs will be read +pub enum ReadSubsetOption { + #[default] + /// Read all pack files + All, + /// Read a random subset of pack files with (approximately) the given percentage of total size + Percentage(f64), + /// Read a random subset of pack files with (approximately) the given size + Size(u64), + /// Read a subset of packfiles based on Ids: Using (1,n) .. (n,n) in separate runs will cover all pack files + IdSubSet((u32, u32)), +} + +impl ReadSubsetOption { + fn apply(self, packs: impl IntoIterator) -> Vec { + self.apply_with_rng(packs, &mut thread_rng()) + } + + fn apply_with_rng( + self, + packs: impl IntoIterator, + rng: &mut impl Rng, + ) -> Vec { + fn id_matches_n_m(id: &Id, n: u32, m: u32) -> bool { + let short_id: u32 = id.transmute(); + short_id % m == n % m + } + + let mut total_size: u64 = 0; + let mut packs: Vec<_> = packs + .into_iter() + .inspect(|p| total_size += u64::from(p.pack_size())) + .collect(); + + // Apply read-subset option + if let Some(mut size) = match self { + Self::All => None, + // we need some casts to compute percentage... + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_precision_loss)] + #[allow(clippy::cast_sign_loss)] + Self::Percentage(p) => Some((total_size as f64 * p / 100.0) as u64), + Self::Size(s) => Some(s), + Self::IdSubSet((n, m)) => { + packs.retain(|p| id_matches_n_m(&p.id, n, m)); + None + } + } { + // random subset of given size is required + packs.shuffle(rng); + packs.retain(|p| { + let p_size = u64::from(p.pack_size()); + if size > p_size { + size = size.saturating_sub(p_size); + true + } else { + false + } + }); + } + packs + } +} + +impl FromStr for ReadSubsetOption { + type Err = CommandErrorKind; + fn from_str(s: &str) -> Result { + let result = if s == "all" { + Self::All + } else if let Some(p) = s.strip_suffix('%') { + // try to read percentage + Self::Percentage(p.parse()?) + } else if let Some((n, m)) = s.split_once('/') { + // try to read n/m + Self::IdSubSet((n.parse()?, m.parse()?)) + } else { + Self::Size( + ByteSize::from_str(s) + .map_err(CommandErrorKind::FromByteSizeParser)? + .as_u64(), + ) + }; + Ok(result) + } +} + #[cfg_attr(feature = "clap", derive(clap::Parser))] #[derive(Clone, Copy, Debug, Default, Setters)] #[setters(into)] @@ -34,9 +126,13 @@ pub struct CheckOptions { #[cfg_attr(feature = "clap", clap(long, conflicts_with = "no_cache"))] pub trust_cache: bool, - /// Read all data blobs + /// Also read and check pack files #[cfg_attr(feature = "clap", clap(long))] pub read_data: bool, + + /// Read and check pack files + #[cfg_attr(feature = "clap", clap(long, default_value = "all"))] + pub read_data_subset: ReadSubsetOption, } impl CheckOptions { @@ -54,7 +150,11 @@ impl CheckOptions { /// # Errors /// /// If the repository is corrupted - pub(crate) fn run(self, repo: &Repository) -> RusticResult<()> { + pub(crate) fn run( + self, + repo: &Repository, + trees: Vec, + ) -> RusticResult<()> { let be = repo.dbe(); let cache = repo.cache(); let hot_be = &repo.be_hot; @@ -105,37 +205,32 @@ impl CheckOptions { } } - let total_pack_size: u64 = index_collector - .data_packs() - .iter() - .map(|(_, size)| u64::from(*size)) - .sum::() - + index_collector - .tree_packs() - .iter() - .map(|(_, size)| u64::from(*size)) - .sum::(); - let index_be = GlobalIndex::new_from_index(index_collector.into_index()); - check_snapshots(be, &index_be, pb)?; + let packs = check_trees(be, &index_be, trees, pb)?; if self.read_data { + let packs = index_be + .into_index() + .into_iter() + .filter(|p| packs.contains(&p.id)); + + let packs = self.read_data_subset.apply(packs); + + repo.warm_up_wait(packs.iter().map(|pack| pack.id))?; + + let total_pack_size = packs.iter().map(|pack| u64::from(pack.pack_size())).sum(); let p = pb.progress_bytes("reading pack data..."); p.set_length(total_pack_size); - index_be - .into_index() - .into_iter() - .par_bridge() - .for_each(|pack| { - let id = pack.id; - let data = be.read_full(FileType::Pack, &id).unwrap(); - match check_pack(be, pack, data, &p) { - Ok(()) => {} - Err(err) => error!("Error reading pack {id} : {err}",), - } - }); + packs.into_par_iter().for_each(|pack| { + let id = pack.id; + let data = be.read_full(FileType::Pack, &id).unwrap(); + match check_pack(be, pack, data, &p) { + Ok(()) => {} + Err(err) => error!("Error reading pack {id} : {err}",), + } + }); p.finish(); } Ok(()) @@ -375,19 +470,13 @@ fn check_packs_list(be: &impl ReadBackend, mut packs: HashMap) -> R /// # Errors /// /// If a snapshot or tree is missing or has a different size -fn check_snapshots( +fn check_trees( be: &impl DecryptReadBackend, index: &impl ReadGlobalIndex, + snap_trees: Vec, pb: &impl ProgressBars, -) -> RusticResult<()> { - let p = pb.progress_counter("reading snapshots..."); - let snap_trees: Vec<_> = be - .stream_all::(&p)? - .iter() - .map_ok(|(_, snap)| snap.tree) - .try_collect()?; - p.finish(); - +) -> RusticResult> { + let mut packs = BTreeSet::new(); let p = pb.progress_counter("checking trees..."); let mut tree_streamer = TreeStreamerOnce::new(be, index, snap_trees, p)?; while let Some(item) = tree_streamer.next().transpose()? { @@ -404,12 +493,17 @@ fn check_snapshots( error!("file {:?} blob {} has null ID", path.join(node.name()), i); } - if !index.has_data(id) { - error!( - "file {:?} blob {} is missing in index", - path.join(node.name()), - id - ); + match index.get_data(id) { + None => { + error!( + "file {:?} blob {} is missing in index", + path.join(node.name()), + id + ); + } + Some(entry) => { + _ = packs.insert(entry.pack); + } } } }, @@ -423,7 +517,18 @@ fn check_snapshots( Some(tree) if tree.is_null() => { error!("dir {:?} subtree has null ID", path.join(node.name())); } - _ => {} // subtree is ok + Some(id) => match index.get_tree(&id) { + None => { + error!( + "dir {:?} subtree blob {} is missing in index", + path.join(node.name()), + id + ); + } + Some(entry) => { + _ = packs.insert(entry.pack); + } + }, // subtree is ok } } @@ -432,7 +537,7 @@ fn check_snapshots( } } - Ok(()) + Ok(packs) } /// Check if a pack is valid @@ -519,3 +624,81 @@ fn check_pack( Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + use insta::assert_ron_snapshot; + use rand::{rngs::StdRng, Rng, SeedableRng}; + use rstest::{fixture, rstest}; + + const PACK_SIZE: u32 = 100_000_000; + + #[fixture] + fn rng() -> StdRng { + StdRng::seed_from_u64(5) + } + fn test_packs(rng: &mut impl Rng) -> Vec { + (0..500) + .map(|_| IndexPack { + id: PackId::from(Id::random_from_rng(rng)), + blobs: Vec::new(), + time: None, + size: Some(rng.gen_range(0..PACK_SIZE)), + }) + .collect() + } + + #[rstest] + #[case("all")] + #[case("5/12")] + #[case("5%")] + #[case("250MiB")] + fn test_read_subset(mut rng: StdRng, #[case] s: &str) { + let size = + |packs: &[IndexPack]| -> u64 { packs.iter().map(|p| u64::from(p.pack_size())).sum() }; + + let test_packs = test_packs(&mut rng); + let total_size = size(&test_packs); + + let subset: ReadSubsetOption = s.parse().unwrap(); + let packs = subset.apply_with_rng(test_packs, &mut rng); + let test_size = size(&packs); + + match subset { + ReadSubsetOption::All => assert_eq!(test_size, total_size), + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_precision_loss)] + #[allow(clippy::cast_sign_loss)] + ReadSubsetOption::Percentage(s) => assert!(test_size <= (total_size as f64 * s) as u64), + ReadSubsetOption::Size(size) => { + assert!(test_size <= size && size <= test_size + u64::from(PACK_SIZE)); + } + ReadSubsetOption::IdSubSet(_) => {} + }; + + let ids: Vec<_> = packs.iter().map(|pack| pack.id).collect(); + assert_ron_snapshot!(s, ids); + } + + fn test_read_subset_n_m() { + let test_packs = test_packs(&mut thread_rng()); + let mut all_packs: BTreeSet<_> = test_packs.iter().map(|pack| pack.id).collect(); + + let mut run_with = |s: &str| { + let subset: ReadSubsetOption = s.parse().unwrap(); + let packs = subset.apply(test_packs.clone()); + for pack in packs { + assert!(all_packs.remove(&pack.id)); + } + }; + + run_with("1/5"); + run_with("2/5"); + run_with("3/5"); + run_with("4/5"); + run_with("5/5"); + + assert!(all_packs.is_empty()); + } +} diff --git a/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__250MiB.snap b/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__250MiB.snap new file mode 100644 index 00000000..092b9796 --- /dev/null +++ b/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__250MiB.snap @@ -0,0 +1,18 @@ +--- +source: crates/core/src/commands/check.rs +expression: ids +--- +[ + Id("50ec36b55a9b35de779a2757571d2e4b16f6d1ca3ff73ade120901262c2b265d"), + Id("d07f392b1dfebfdf50bb10a4a7857b543cbe246f84549af8902dfde9737fd425"), + Id("f879520cb3e653a0c77dcc37dcd813a71ec7d972a4a6185b13f2ed240c6e72e1"), + Id("8ba2cc8cf44054f35be413f12ba83969deb01f1c44660822cee1b960d69a7526"), + Id("e6bae2c9c6b9d8b8a72b45590ffc6c8e034083d6a8180877f6d270537a1ac214"), + Id("f77e206f69693ae3490de38ce00f5e89ae7db4808b770c60e07d64815ee0478d"), + Id("20b51c8c49aff07d7063c76a863cbdcea845989ef79d4a3f8ff599687eaebe48"), + Id("9630b7b1e6329e7c28eb0eeb4e0df36bbf45acf3ba5de4a0403b77e47216857a"), + Id("33e053041d2de235e03cc219a8b8300d8f1e35ee034c45f4613ea782d5e672f2"), + Id("7583c1099bf604771a03af7627f4122a59da07db7358484b8543e881a7939b3f"), + Id("a94f61701a165181c6940584ca0cd2c2355e5e1eb65a3a295fc4d1c02fa81138"), + Id("5ae22a813d32049b56ac2760a5a34b8f66e30b5232f66bb8eae420c7022197e8"), +] diff --git a/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__5%.snap b/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__5%.snap new file mode 100644 index 00000000..03cedb28 --- /dev/null +++ b/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__5%.snap @@ -0,0 +1,41 @@ +--- +source: crates/core/src/commands/check.rs +expression: ids +--- +[ + Id("50ec36b55a9b35de779a2757571d2e4b16f6d1ca3ff73ade120901262c2b265d"), + Id("d07f392b1dfebfdf50bb10a4a7857b543cbe246f84549af8902dfde9737fd425"), + Id("f879520cb3e653a0c77dcc37dcd813a71ec7d972a4a6185b13f2ed240c6e72e1"), + Id("8ba2cc8cf44054f35be413f12ba83969deb01f1c44660822cee1b960d69a7526"), + Id("e6bae2c9c6b9d8b8a72b45590ffc6c8e034083d6a8180877f6d270537a1ac214"), + Id("f77e206f69693ae3490de38ce00f5e89ae7db4808b770c60e07d64815ee0478d"), + Id("20b51c8c49aff07d7063c76a863cbdcea845989ef79d4a3f8ff599687eaebe48"), + Id("e9d65ff27f350d46ab7b1147511723ad88a2453311ae209230072fa3ad7061b9"), + Id("9630b7b1e6329e7c28eb0eeb4e0df36bbf45acf3ba5de4a0403b77e47216857a"), + Id("80d81feb02d330b1b19847eef1799b5eef1f49d86b5868a5aac20489765690ec"), + Id("4fbdeb3d00095e28cef9efae2c412ef8a22e685f90fa555eaa6bcc37b25c6508"), + Id("73400ac961c6e3d938ba106167a73495e76243cc531b6487fbbb9f00c5cb2818"), + Id("0aecc98eb1e9c7ab4a04a0fa3dbc86ac17f7448e05bdab4f59f2761b86ed5e9c"), + Id("32fb9db957fc10ac2812e9490533757f17602dc0f514e0ef7cd4d0a19645b6b6"), + Id("57e3f93b1ac0928db8a55e77824e043bcf25ee28bfed1e60aaa9d568dd79e574"), + Id("1afe739c8f3703e6b2807107db592d0ef6269c43a44716e08f99311844904b87"), + Id("ed49d37e5e9404c82f1373c604335b546e962b6b997fea552ce44a1ab12765a7"), + Id("b7c3c37a41c4504ed46348908978eeece1732e2414d6eeed10f3b27fb07cfded"), + Id("213d4565ca5161123aec22060b362fc6188e2ee41c11df09e5db868050c251bd"), + Id("476746a3956f3fc56c4391c1f2a6485de2e707f97b43e6fde302d8ef58d03b14"), + Id("0e5f2ece590104cea9da3366217853c49f3ebbd949721a1ba225648453a6158e"), + Id("e2c2a4449c2fd35beedfa98d006f9ec2c638c41e745dc7e51c45c341abab1769"), + Id("0bc1f65e245a4716b44b80f79fe66af53caf1625ec57d94ed063411f04fef7f4"), + Id("adf972f778d97c5b1cd00e2fe04954af594a64e7b8b018e7e572794a0c33f47f"), + Id("d2d5c26249cf84a2822c710edfe0e9f10eeed8ae74cf318e0530f6cb08c51425"), + Id("cd3049b4967c028ae7459698cdc110cea7eb197c60d8a7488f2793a0f87a47d4"), + Id("bac90a9cf3bcd7e7222369bbf00dc9de9c183780a0e602a6213f8c1134fb22c4"), + Id("069df78d3a7f51f0171a9d64ed58c1728fc0f86fe725680d920ffb384d0068bd"), + Id("b0aa5dc32c279b4a9b0c026e41fe0925b12f70a32d3bb854110c16dcf70ae9c4"), + Id("33e053041d2de235e03cc219a8b8300d8f1e35ee034c45f4613ea782d5e672f2"), + Id("a39e69f47f6617866beeff292c25613aa4776abe8f11108035fa38bc72030c59"), + Id("7583c1099bf604771a03af7627f4122a59da07db7358484b8543e881a7939b3f"), + Id("5ae22a813d32049b56ac2760a5a34b8f66e30b5232f66bb8eae420c7022197e8"), + Id("01324e1657f32d887da2be566b060d1f53902a399498869b56f942cfbae50705"), + Id("3e26211a1a4e63cfaf22d5f3e4c87a0fdc521f177535620336301813d4a335b6"), +] diff --git a/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__5__12.snap b/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__5__12.snap new file mode 100644 index 00000000..ae3f8bb4 --- /dev/null +++ b/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__5__12.snap @@ -0,0 +1,39 @@ +--- +source: crates/core/src/commands/check.rs +expression: ids +--- +[ + Id("ed49d37e5e9404c82f1373c604335b546e962b6b997fea552ce44a1ab12765a7"), + Id("05f409ef8f73a6c4b6a56d8782f79756955576a285a3c39bbd674a29adeedf90"), + Id("b13349f4e2b1ff600d17d3aef70f25cc4d5ffcd8ba80e7f3c46b37151641d1c5"), + Id("a16680a002905ed49dbf84851f5a4d0fd9a6ef7f783a69599b2845689fd3774d"), + Id("2d02b51df763489e64ecc59c0678dfbeb808e75775d11f6f4727aaec7cd5763e"), + Id("b93c546011f8f398d4bb9351bab79b91693b02208ea4b6b9860bfb8c9cc5a25e"), + Id("01c12f4c2f68e9e96fe4935242fac755a0ed9d6d8f249c92ab234847d141930c"), + Id("c5bc2389666a913dae6254dc0da0c2a4268778b0f2aec695e75ddefd5641f2ba"), + Id("1595155af06c09834c46936d921e0e82a225dd7bc54f9c045ba7e710b569a2e1"), + Id("e5b2e72d3474bec236074943d8bfafe88f16462f81629eb8faeb4d34ac06bd9f"), + Id("19fdef223293ce96c81c383459731ab2d973796815733bd81880819ebca414c4"), + Id("01a8cb9bb17f736297f3f2d6c870c3c63aa518180f1f65793d56e993a39031ef"), + Id("cd3049b4967c028ae7459698cdc110cea7eb197c60d8a7488f2793a0f87a47d4"), + Id("ed86d1d05d6693df14f32e38a692cfac5634cc5b075fa2e7206d4fff9dd93d4f"), + Id("39e85ed58a1ff03a9d340d18054e70961a5af0cf39dce2857488563804456f52"), + Id("ad980c1316495d55ed49233c8adeef7f31c50e3be033da73aba884c42de9a7c3"), + Id("25b85442540500c1542083649b882be38d47243b2a46d1b6be9b7a4866738a56"), + Id("35fb0a065bd90575a8bb3acd9b315f213bf0880a52888ef8f875847085ee3f7a"), + Id("1db4e7abd8f7bac90caca9657fa131bbee769766f425a1db0ca6e9cb5b92adcc"), + Id("198d4ce71d42827765fdab01f65f765469939fb7a14d172f70ec4b8927a18799"), + Id("f53b922989ccc6656ac96019b18a8a11f067e97e938493549fc5f2db1f84cc84"), + Id("55d2f4278ad11c8713274b81d88b60d06d625920360ffdf0e01523bdc52abb47"), + Id("191104767f95246d3946f77375c17d692f55deeb8a61ca4d0483868b3aa0f807"), + Id("450290b4d8be35d70831cd8e2d959c0f6ab6753f422c69781655e3702e488280"), + Id("c906750bc6fe5d788237fdf61565dc1d0bc95241ff62cc5f24c719f08775e460"), + Id("4d3dee0ae9d3d46263a51783802c5ce8995261d03946ea8f556273b018393436"), + Id("b53d3c0f6e3a43c9cf35c68831079d4ad3043354558d52f9941a9c1dafcb86f7"), + Id("49940c21180815deccecaad0f7d9f3114edcef219d889c38657ce88286309f71"), + Id("2dae514a1777cf8ac5d78402af32234ee60e53bf1e69eb2214831d7b3a576829"), + Id("7112f32a249a72883663a3c52a6c49b46429c5e5aae9e400e7e2d7aaba2ae828"), + Id("255d2a4fbbbbd47d585e5515f3f9b60376970bbc692592d57d4827949b99537f"), + Id("cd10ef439ed00c7b3ab758d35195d2ec87eb2465c7dc8efc4ecccf8bdb7aa12a"), + Id("6d363e38a62a8ad3937357ae55057afd7edc5912ac840842145f3a43b07fdd75"), +] diff --git a/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__all.snap b/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__all.snap new file mode 100644 index 00000000..f5122227 --- /dev/null +++ b/crates/core/src/commands/snapshots/rustic_core__commands__check__tests__all.snap @@ -0,0 +1,506 @@ +--- +source: crates/core/src/commands/check.rs +expression: ids +--- +[ + Id("7a19fb2d099a9557f7c10c2efbb8b101d9e0ec85610d5c74a887d1d4fb8d28a7"), + Id("192686bfeb57188612bc925d2019915736c7eb2ee481a4f2134a7ba7e216986d"), + Id("d12533cf7429a193c3eac3887865646a2c11c2c7701e8a72929bd6b98d971357"), + Id("1252c850b5b8d7b763de96ac7d74abe977fe26e8259e0d5dd52c7a3b47ccee17"), + Id("e7b0e7132ef1a1a18ba6737c519702114ea511c80cf05640f14ea87a56ee1427"), + Id("a4a5504d4fc23e3f4be3747302a266102c4bfb78de823b03597e882b495119fd"), + Id("2a7fffcd525047637ef5acf6138894a33cc3a1b6a8adfd1533294ce6661bb4e1"), + Id("33454d7206ac66426b964a09978f710dc4a5de9992a85fd23ad055e4343b5249"), + Id("ec3b626d389c0621124de001eb990503b4afb76ef1ec0250a7c7e4f27db204c9"), + Id("bb7c539a7bb73253f9e5957b06ae81b41440833fa69ffba858c535a8e259bfcb"), + Id("b63b4ab65338ccb00445499a28587b26632d026d3ece957361c6bb547446b697"), + Id("ba8e271c9a3774a55f729a5315cc2ccdb6f0ad4b683e8cde2901dfc8d5f0fec7"), + Id("463040ecee9b4176688730a4cfccbc390af6c9add148b6e703fdf2ba981d9bd9"), + Id("932dfa541035fe178289e5ed99147711d1c8da6c2b3866ca4d94b5d6afd06ae6"), + Id("c5be384cd4f785e05bff67e5bc558971b5197aa67cb52ffba0c772aa83584081"), + Id("bb22d2d12df0e239b7b2d949cd59a2b435bbd7c0cc017ded665583959dfe2483"), + Id("7d89f5c9242d47bf6efa3498f8001e450f0aa67771ded1917dbfe0ebe4315ff6"), + Id("fbc2189b41678501eaaf544a37bed25f57b9bd9fdffe3d3b9313d1a85765713a"), + Id("ed49d37e5e9404c82f1373c604335b546e962b6b997fea552ce44a1ab12765a7"), + Id("32253548cdfca44855be2fb1eea46aad956227a645a590e09ae3f288ae002245"), + Id("dce11e534b0a335638c2069b4c090266aeaa0f142c92478d9a6e06c3f20e1eab"), + Id("7fe3e2d623e8575f93c85a92ef3fdd0c49c54536b8bdc3a62c423436cb04130d"), + Id("d4a533a27d15e7166ac3cc6e3fd531a0475f742bf30b5fcd4daf5166bcfc0d34"), + Id("05f409ef8f73a6c4b6a56d8782f79756955576a285a3c39bbd674a29adeedf90"), + Id("d49d306a001a5bce4e4c8609b88e050bd5aed6cbc9707d3f7926c15949b53a22"), + Id("339f7f946eb45a3cfffbe245517f0fd6fed128603e3bbc18ae65d6fafd4853c2"), + Id("204a3c1ee87a01ba3784753736d9a412ea2c954d6468c21d240f1ec51779d342"), + Id("7f2b31f79fac8c3da8341d75610e0ba9b113f4b10454a53f6189e75594dc2bad"), + Id("b13349f4e2b1ff600d17d3aef70f25cc4d5ffcd8ba80e7f3c46b37151641d1c5"), + Id("7951d2241ffe99053d1444cd0aa1063a650469d2ddab1b71bc018d7624ad22d6"), + Id("03756334b251d523c57ef4b120ee1b353cb9fc784acc43002a767eba35f76a7f"), + Id("b7014243af4a6ccc208f687f66c6dac83222219c191dc430da96ac8a7a7a871c"), + Id("9c7aa22482dd5a1d99c74fd3b284dc3ce720c46636b08a809dd4017873c909b7"), + Id("f302025ce933f9a5e2db78354d91c3cefd7f749bdabf0c1eeda656f33ca7177c"), + Id("7452e7eefe985c291ed89a8ac1167c3075e17bcab04effa2875e0f2f8d4517d2"), + Id("0e5f2ece590104cea9da3366217853c49f3ebbd949721a1ba225648453a6158e"), + Id("9c225b8668d5195501abe1b59c2e041672eaf52c4225c6b529dd98fcd61bf8d4"), + Id("d80f37f1d4a75210aab118a98f402bb5d2359638b93b537b3c2bbc92a5240d69"), + Id("476746a3956f3fc56c4391c1f2a6485de2e707f97b43e6fde302d8ef58d03b14"), + Id("1a8376a5e142fbaf30f787bad9d633a369b1e8886bba90b2f37913f391cf7a52"), + Id("1ff996077d132692ce252923e15739f992427beac35b6702d12ccb79743853b7"), + Id("ec4ef837d096d31f2a17f86e38878a86147e5a2e9d41bbfb91b6fe5a8b06dbd0"), + Id("290a6642717dcb4f27462beec0ab41d8e3a004a056ac80631e8e4036a8d1e92e"), + Id("928e95abec1b4407aa36b808c4d55b63d8b5c086135b03b18cdee03022e75c81"), + Id("d2de82ddd23398afd62e7cece5a8a90199c48cc1ab1461cd9c7ea289e4c11746"), + Id("abfac5641607d8aa62950d7da3d6adec6695ec2dd22ce1f98134c08d4edbd493"), + Id("c835c29e43e54af94bf4f6634f33232472b1bcd524063705b160f77a83a6205e"), + Id("a16680a002905ed49dbf84851f5a4d0fd9a6ef7f783a69599b2845689fd3774d"), + Id("a8c2322ef67d74f180f12aca6365d593bc8c847aba55cefb7efd2fc3b87abc46"), + Id("8be0c32b38ff750a28f5166054d6397b2520ff8c9248f6eff8c7c18212ddecfc"), + Id("2479ccdaa110bbf86b94e01dc26129e0d2d0a251159c55ac93629fa6e8fb048d"), + Id("83bea062cc0241b9340cc38f97c07df83872bef697ffc55b25abe0b234a49a51"), + Id("152c04e42487072c587cab03d8841b4be30659e1da0e5091f511171b938c9bab"), + Id("7433f50a19c0b22fb08dc761195afb6c56a9e5e2110dce567eb7743acda9653b"), + Id("c2163af883d73a4bafea6eead7dcdac1fcc869412ac91112894b41bbbe417d58"), + Id("4ff524695a42b8f16232694597a4e3cdbcba7c996d0302aa7445f55e26cb905a"), + Id("ccb3451d873cb7dbcaf2f4869e191f7965a65e6f09b0ff13757537c94ee0c090"), + Id("f1a056b0753c89067bee35e29d5341968b58fb5e47372eb6e2d8d38a944569ec"), + Id("0108a1f7db43a040bbbf08ab5c135142a224afad4220d29286b55ada22934480"), + Id("12a660fded6a6fca4af9cb1b723fa9cbbc38209df61cf5bdd1808d80451a8acd"), + Id("76f65ed4e2dee82eb6794a0bd7967734d01243924ea035d74e474ea8c8f211f7"), + Id("2da85157478d2258f8cf72def779b764273671fc3dbeb42bedefdc4d47ab434d"), + Id("edf1894034c9c427dd7699384e0c4f8d0ab110749df67043c30c0062cbcea5e4"), + Id("4e203c6d869f0eb6aae2d76f452366480302783453df9a533fae7c188235d45e"), + Id("5b6dfa22da10ddbd7a5bb3017e9990fa5aea5bc7d82e03df6ddef1720357f912"), + Id("2d02b51df763489e64ecc59c0678dfbeb808e75775d11f6f4727aaec7cd5763e"), + Id("bd8a48cde49a2bd6e7e2f3da04564a144de71d7f99b9fb42c156c2116784a627"), + Id("275111b699ba2cbfe146127c05bb81b2cf39c90d5e0130db19977b552d4ee35f"), + Id("d2a4d78e92c9141ebaf5822355474484bd6b9e577c5ae19e84900c938ca2858c"), + Id("f0f9d193afbb96f9c354cb7ae2457cf876ed6ab000d43fdeb926984f2a1a7250"), + Id("603fab5f6016da60ecda6f3f973b9ebd18ab12347832b967fd1f354dfb93b882"), + Id("eb97b2e328a9a7491c5b4148b8848f0e2931dd10a8159fea322f0d0d110c8d4d"), + Id("1353bcff7233de64f69c24d75c5044a5cfdd924b6584ab18f160c8dbedf341b6"), + Id("5bcecb3009dd07cf5346fb3eb0d576e871329908db9857188b9c3bb893edf0c5"), + Id("988d90243d75973a639b8031d3b87002baba7b05ae47299dff47446848f9ee68"), + Id("f0fc9711b515df80ece0068d9739a49ada6b5bf630f04faecf18cc302f32773a"), + Id("8716c820dc24427be99d7c122c862c20dd9667186dad55e837e4888443139351"), + Id("37e1e8b63c1bfdac5535f69ef7969d7647600cfa3d59c155601d17a7de49bf40"), + Id("63b1fc56a51722a5271938fe72dba075d5b823a33feb20718f16b5da26850869"), + Id("87c418b7102dbca43bd4215b09ea0342109658f772e6b57f05de29862fdd4e49"), + Id("6d441446fa53219c782b646a22390f57c71de5437acd6349bd5f9ba044527342"), + Id("d7c45bc8be4eb748117db5cfa26fb27a24a487fef77596d823d134a6b76e5752"), + Id("9cdb5202a444dc5ef994b68c3889e2a890318f5f889f41916abe65085876fc7a"), + Id("b93c546011f8f398d4bb9351bab79b91693b02208ea4b6b9860bfb8c9cc5a25e"), + Id("58151e9ae5400edcdd5aaa33ab2154da5ffd734857dd5d976d46d8689e277db0"), + Id("41902918ffcb54b77aa371ace33b6fcf6f123fb40187b41fb6df3818951d7a10"), + Id("8246cc0caf72b4f1bdce2dad938d70fa27406606d07f0f4806475101644cf0fa"), + Id("4fbdeb3d00095e28cef9efae2c412ef8a22e685f90fa555eaa6bcc37b25c6508"), + Id("4fe9bbff1f6bdb89654fa02115984ace2b3a37f8ba043ec7ee1b2470fd60f4e2"), + Id("0b71983cbdf64b905051e61e5e971defcca36f21f4977b4689ca04489182eb1d"), + Id("7583c1099bf604771a03af7627f4122a59da07db7358484b8543e881a7939b3f"), + Id("f5fa8530976687cf4739859e08778fa59f59f08ef09095bb4d897ebe0abf4def"), + Id("dcc35669157eeec474a1968ded28439b923b6379c6e9eb4d39ec7f011205ca2c"), + Id("2ffc61d9a16f5cbc93a143ec711c4c7b9c1b2f6f3b94c828fbedec4314295770"), + Id("d8319a8babcc71eca6590c068c201ef69a09550d9f938b3bb47caadb46896829"), + Id("11759604148e92dc649eb108ef580f2b4041e1c9d42c5af2d90fabff884c5d83"), + Id("966657fc55521db10ef5ba227eb76fb2e235d4fb1d833a3d4c1f843547719fff"), + Id("18087189d7c87e059e6daca80d96af9bc655e101949ad51d0923a6152429b923"), + Id("7c3b938ff3142ce81d69c3e57dabd7e428f28ceed2b64c0917582f9fe9e9f2ce"), + Id("446a451e2afc2e67491fa8b76bb67eb0fec9823506869fd1abb014989b0ecff2"), + Id("33e053041d2de235e03cc219a8b8300d8f1e35ee034c45f4613ea782d5e672f2"), + Id("f2f2e429d6f5aa128eec6e838d445af0c56b13ababa311e0a332970442770933"), + Id("73400ac961c6e3d938ba106167a73495e76243cc531b6487fbbb9f00c5cb2818"), + Id("02c8ddc25e3649354765dafb477947cdf55942a7e382d102d1d9b35bb6bf5e48"), + Id("bac90a9cf3bcd7e7222369bbf00dc9de9c183780a0e602a6213f8c1134fb22c4"), + Id("2b3f7f830c667dca9a25301e365928cea5c966b8f67e63f234611754bbfc40e4"), + Id("008c7c271f249505b2f93513167cae56a47c0836d51a86755ae3a9b5c6d150db"), + Id("19f6493ba94d42e321bb14c024025216eae8760cb9b62eb51a89b3e085405b4b"), + Id("b9938f5189afa30fe8bff9f475ca357a81bbfe990036b5063537e7eca26fd080"), + Id("c4cdcbc5adcdedb1307694964b2d339f722e52e2566893a3ba9318859bec6395"), + Id("3c59308f09b13f23342146775499b3bef716ca0b14095840b29098e56e0994fa"), + Id("817394a93b36971c2ed445020a15be2d08edeb9f982e76f9c4799a27b4ac80d6"), + Id("0b27a36ffe426a50218b07b1977e9ebf4fa6735c5b5735908368974649f0583d"), + Id("f07e15729da52e64557824e819eaa74dc1d199e59be5ff878ba8fdc8f3ad73d7"), + Id("b64dafba16990f278c5c4e3f7a8155e081c16f9d45ca7c83bd6fdd2783fcb744"), + Id("2ce747263955f061fff60d897034c812cbc68260e15a16d44f8a756152a8687a"), + Id("26e10ccd991dd90645f1a353c168625c77120e363864cd01c0a620f21e43b897"), + Id("11f9d4298d0c966e566b56a997ee6bcc6ee1ee8d8536142dc30fc5e83ba89b92"), + Id("01c12f4c2f68e9e96fe4935242fac755a0ed9d6d8f249c92ab234847d141930c"), + Id("e600f13324d48c975aed4a6c662be4caf840a78db58ec7128703b051ae82a2ef"), + Id("fd6e82f2379ba03da9941ba1911d40517bcf6ccd611225718f1bf80b8d689933"), + Id("730ee15435eb5f73dc49d172f0db9eab4ec159b02324155450ef9d40cc16211d"), + Id("a0f6edd332de2b5811afc33f04497b0587951304382b3bd739eecb375ccd5bdd"), + Id("d8f0aae5e6d2e0262e8e76a0619b4731eadbb2bb297aaabc742f06c7bb2b495a"), + Id("6f929ed57b543925d3822b0024778d19d03d0c1583bf68f411cadbc0b54c750e"), + Id("01324e1657f32d887da2be566b060d1f53902a399498869b56f942cfbae50705"), + Id("66d21c804152454c5d9df806536d1936942125afa66e29d7ae4601735b279941"), + Id("2447a8c4231863956b42e5df0edf90323683900ea329e8d50f4f74c06b20075f"), + Id("89d9ccb88ca28800cb1fda041f5dc9e63afb8c52dc13b05498c2e787bc0e609b"), + Id("e364383af7fdf17656d35e5cf928fc39ffde9bbf4b3c39262f75dc2e0b1b93e4"), + Id("abf589556a8dae41c992d42e63d1c6382a516b9c0f4f4fd8991dd3471d3e6ea5"), + Id("e2b333a2d1b4dc1efc08b5e90ac111af3d830421a532b6c08c27dc8d3d223752"), + Id("be7c7ff7fe6fa27d850ceb9497b577e85444f4266fa09099f786ca2cd64efdd7"), + Id("160dad1cdfc60ba38fb4ca55a07ea1c7425db54b12d51b9344badaf00563fc6d"), + Id("b9baf9a09055f89d7988d7b87c80f07487c8deac9b7161a2e1d45a3ba0d142b9"), + Id("814928f12158ab1b018174cc3f1905fe14367b43b2acaf712eef6eff1a7389f6"), + Id("709f127bd285324e88dd20b988703f67654dea6eef317d49355a0afa097a3ea5"), + Id("6e104d5f886eb5c4c25f3ef626906d1f21a5ca205946f9ce9167654d40d04515"), + Id("c715237e74fc52a456555ca13e1905f4e6a8abf8fe95730e699be0b65235a5ed"), + Id("3496213dcc010c74eeda13bf7f81326b7882bf23a1034b328e360c285d72f599"), + Id("c6e9be79236a15668edb19881ed812fbb2103c2b57f99dbb0c175460d1eb03f9"), + Id("d49241f420d8a4a131366f68d197251cec9aa98f597da01515fecbcc7dccb34f"), + Id("4cd1356c08cbb79070749122a3bfe2e8a74c0573337ab13c8657ea652cf664b3"), + Id("ffb342ce777294c9fe707eb0cedec9e864723cebfc751ec44fb65d48fb60a1d9"), + Id("6afc413d3f801a4de998c775b34ea28262bf8b5386b81af32b7da9382a348405"), + Id("1d115c73051f9add5b39dde92931df2c90f6186bf89b303ab130cc228e1b0ff6"), + Id("c5bc2389666a913dae6254dc0da0c2a4268778b0f2aec695e75ddefd5641f2ba"), + Id("c387c99d8e9ee88ae76b1ea9bd3f8cce2e885ab6553c4298402e4e2a3c87a281"), + Id("f12f624093bfc33dc932e37c10cfa5d766c00fc7b7683f561f6a89baf644f67c"), + Id("1f886d441128e339f19dbc7e24565acd2a6813887582b324bf91e4d7c17b3b60"), + Id("83e3e3434f410698740bfb6c49ffa697de4df5fc9443e05402648ec5fa873e83"), + Id("edb8c3242bce0dea1dd3338a6641d32235a4c329703b2f11579c154345daad8d"), + Id("b78ca983b3e09fa3f87f850da30918a9235ac34c0fb0ce7f34947a35d03b9a40"), + Id("0972c10031df955060341e691232d236f27504fd6a37d689a60cbcd8e0583559"), + Id("dd8c1f2bf2a4488c1bdec453fb0b3a1cfa43226715fb7e24072bde73356be867"), + Id("627a2763bf30c0a9efbfb857278e8599d3797985b929d896ecf69015ddf5e4af"), + Id("fccdea6fdb4db7b88b9706f0759386718798dc4228acc6d48e11083b46568327"), + Id("fd4db9e91afd5292541699523885d82122c6f2208d5a2136118d0224e7fdd8b1"), + Id("e7e0fe067cb65c852b05801871104283bbff9edda07f645c291122978c9270ba"), + Id("a00a23bd0e91c55932f1f6bf3bce769ac96038a344c2ae15fd099312de13808e"), + Id("c57d541143cafe7da99c02cdcd389e7148415d0e951088c0bec1f556ab5b3679"), + Id("20d74f117ef91c8f345f9e60ef0b873fb1b04cbcf8d1d6663a99ad98c5bcbdb7"), + Id("e6220034ae2c1a6de8813c510e968159c4184ea78ae9dc99f1aa852c716eeca9"), + Id("caa95c3b2bf3a13c8c484332fe40d081f02660f818f141e26daab240d552fba9"), + Id("9630b7b1e6329e7c28eb0eeb4e0df36bbf45acf3ba5de4a0403b77e47216857a"), + Id("7c43b0096a8894fed4bc5cb4db82c976445604bf1960929f2f9eab8c0d58603c"), + Id("f55830bdd94acb52bc57e2e9a664984f6c1c12e8c5f16ee140ab86c3cfe0d0cb"), + Id("abb44dcbbd049b29f59a9d8a64c1fa8fadfdc585041112925d7af948471c27cf"), + Id("20b51c8c49aff07d7063c76a863cbdcea845989ef79d4a3f8ff599687eaebe48"), + Id("50f6a13124e70e73e9216c500b3799c5ff6b7bec03b8764c4cc26a2aaf560bc1"), + Id("f8a6a81916d3808d5b73197160af65183eb5a04418af8314e10d0ee2c8a9bbbc"), + Id("312390018dce2b9b0168047b637fe243b304258f147df8dca0bada4623a5b452"), + Id("c4f92979a1c6f7b801ba95fa2031f3becceb4b52e962eaf04245d6885c7568be"), + Id("63064bdcec40fd60ddda86d2e80cfb5a4bc1f3c71bbb1e4e3d442f42403c8445"), + Id("4ad43e30d43b6a22a01967447ce06f6dd3d75cf7497e512c06526e69ac28ec64"), + Id("dd8d9cb677ce876c689d0e01cd72c44f64f8aae9e059bb109368bdc332b4d470"), + Id("2e8c77411a4eba5e5b13ab4c343c63c40a42dfb769d9f07fe3173b62f0a0344f"), + Id("8c2fd402ecee7a0bd886617d7e4b5239f2838a50260e154a3ff0d4393820a1f2"), + Id("2c31c03b2d1216a2568e5a077c9171b369435007be96ad8cc4e4d41d71c761c2"), + Id("cd9bdc5a61cf06117ea27fca791e649705b2e5b505efc6aabab24bc6ec0876aa"), + Id("9b9ee0f9051f2ae269a21bd84e3676506ebf744d98191bd60faad68832cfda48"), + Id("ab7a68ad57ee0f24ba71c17487f787108dc7a98fb28c36c40a5ac6c8a2cde39a"), + Id("c14f57bb89cb17a1a76043ed1a52c635638de1c12db1b5f3abb67a34dee28acd"), + Id("26943e266be42c6c58e1a307a7e41de5406d56b57e4ec5d01d570dc8f79a7122"), + Id("497e0fc8ab7573575d07f29c3585a931552a760ed1fc33047e3c975e39ed6a7a"), + Id("80d81feb02d330b1b19847eef1799b5eef1f49d86b5868a5aac20489765690ec"), + Id("bd90a75c82ae0f090e24324b810987ef1253f7c348a19845e15b87bf2b78de4f"), + Id("87e4a01e1c93f5c910442820a342d8920d6f379e6d98be75506fe10739cd902e"), + Id("bf4906ef49f5001d3e71cec8b8e4c7d3bff21ad96a74ec7d3616454bcd0ae57a"), + Id("e2b0ec5a4817289469b004d17f1c4a4192c59119a1460c4799b76406a1524b4b"), + Id("fb65b72e722bc31af209896548619e962f7fc9b93335b77b3e498c123080548e"), + Id("23c82ede768b38f5a3303a951f16eb658b0f5f6ad932415604c59e9d797053fd"), + Id("976f11b7ba9fa0ebc71b4dc72318bbee0989de940127a3e61206c87fa8bead25"), + Id("51e45d30db242f09b00fe56f52e4104309850a0f44b8c4eea24915fe5a12e22e"), + Id("ef4445f9f8efbb46c16d17f1e4f6b26e097967d57496d5aae6d9d9c7eb7fa06c"), + Id("643daafcb37354228fc4938d745a060496e517424cb5d08e06ee87b2efbbfda4"), + Id("532c678332ccde5ce2559f5c9f5369b82492e0b661b1e20bf928f0c41e26bfdd"), + Id("20161d103c7de24e5283c7fcbed42103af262306ccadb65c898b0dc2a6d0ce04"), + Id("179798bef6459d2f73b89c4411f36e7e67ac518e01419d357c395d2140d6a6c4"), + Id("2a5c5b1d1c7a5454151118714cdf746cd6428d053523533b5d8c289501488949"), + Id("c2ed86a3efeebf4ec8014f02cf68ef4387b57e8f08219f89111d913421a86a28"), + Id("e2c2a4449c2fd35beedfa98d006f9ec2c638c41e745dc7e51c45c341abab1769"), + Id("0a6f539a2285f3e762b056780ab3f0032b87fc6da2725bc1627bfe2981ac59d4"), + Id("5ae22a813d32049b56ac2760a5a34b8f66e30b5232f66bb8eae420c7022197e8"), + Id("31054b0c3842315fcaf887fcf3dcfaf5f59a2e34a054e40fb7e87ed7de14b6f9"), + Id("24e65da2cfcccfc9987ce1e70cfa993c0dd8b566fb3b21a21148ae49761b804d"), + Id("93d96b7b87f0350a410646497c3a120d6bd14643cd25a3bf5d9d7b3237b3d7aa"), + Id("72ebd4e56a5de9a48184ab5e16b28a9bd7dfc7e32d83a695aebab2d55fb62acd"), + Id("ba50c162c39e4a2c1f1641efe75237dd93ab3f54148abca3028aa788db66b760"), + Id("aaf3777ac2729e0a232159c483f80e385cf9085e0ffcba9df01214d951538f82"), + Id("86ba06b88c5e753b133aaa80d0913f2ec6becc4b955f2886e1ac000553f01010"), + Id("471dd6c326c6b1b7e3312be0250992c192252a704f4142fd03a7c0c297e6796c"), + Id("90e3c55c3fe76da54346e1dac1733ef81594d97d4ebb0aaaa54b621478e7e057"), + Id("40576d9d46cdffe7d75b84651f1c9ee9d29eee08451af5b71955da0e4fec2f24"), + Id("a94f61701a165181c6940584ca0cd2c2355e5e1eb65a3a295fc4d1c02fa81138"), + Id("1595155af06c09834c46936d921e0e82a225dd7bc54f9c045ba7e710b569a2e1"), + Id("e5b2e72d3474bec236074943d8bfafe88f16462f81629eb8faeb4d34ac06bd9f"), + Id("72d7e06056ede3f36cf9546ff0a2345fec2413b9d501eddd46419487ad56dea4"), + Id("893ec97d3de86ee4b6fb78d1ee870528d285324fb5b9a40fbb785c95f3ee8491"), + Id("b59d53413d80c8ebb58ef2cced339ec4135efe9bb6bfa7de045e29384dd0f3cc"), + Id("cf86dee92012a7044fb6e8ecefda2daecbdf4eb57caf616cc8255604ee6cfe1d"), + Id("987908952acd5399e7d76ce03318a7fba7265a3bb10efb1a75d0158dfd9c0b7d"), + Id("631dacb96ce3239b7069ed3b790f6c46bc8237ee7f3cee8c6979bd71d3ec5eb3"), + Id("08e8c5bcfc2bb0d94404e17e946a5e65747d04acdad39cc62647bcb2fafeda5f"), + Id("f6793ecb58b90a672731ae26fbbcb0b8f6f6673bab039a5b6fc8bfd7fa817d57"), + Id("007b697ae5770ce471dbaba74fa86cd621578e570501e7eefdc132624dd2e69f"), + Id("d5e86d0d59a2172f9b3cad6324fd787956565f608bde9ea1a635569cc92ed388"), + Id("e003cdf544fcd69e2f196d93a2478598bac8aa5d4411226b240eee266a87c7ca"), + Id("b7c3c37a41c4504ed46348908978eeece1732e2414d6eeed10f3b27fb07cfded"), + Id("81aef66fd6847aacf28543dbecfad3519395a521aa2f78dc89ce6e5d0eb394e3"), + Id("19fdef223293ce96c81c383459731ab2d973796815733bd81880819ebca414c4"), + Id("2485e767bda7281362953f92e2edab35a2787b8b83d088fa92dc087001e79376"), + Id("adb50a63a558486581ab7fdd77ffd265bcaba6a4df26fdc14d0d0a089d7960e2"), + Id("773c61e7c35f4dbfee20dda18f616dad8c4ef911ba96aec673213fb61b1387f9"), + Id("701d69460d146653fa52de674d51926aff7ba44c2d18b8bfad33b98cf8ab4a52"), + Id("6dfdb408368420e408fde339c9c760b52915d0a505185b1aae76e30a86938ff0"), + Id("cedf62be2abb9c122ab597d4ca9280ced587cdeb7ffbf16710433fadfdf054d2"), + Id("f1df76249279e7db5722fd9b4d843f8b2386432ef24aee49b49138156d7723c0"), + Id("de3861b2a517369cf4b8350a9cf5e4ed31ef307a2921a59ce0b337336fc4d5a6"), + Id("ccd427e073d552a897daa29e93e0239d01b79a5f6ad37a7161db7f6e64275a65"), + Id("cfe97f8ce00032ffed907564dad33838fb83133de135420c36e1834dde12f825"), + Id("7c404b9e0d62277d32f84298fddaa32997148be41d25d578b7f55d1339fef0ac"), + Id("c27667cf031fbd54135525668fbc434299adb981dac195b34a96c90f0ae76c2c"), + Id("afebf91cc95dc55c8f79fa02ff8e54c4c080305cc5e0c473fde0afb089180306"), + Id("d09d9cb6bd689d2cc961824252fcccca75cb0f6e0a1ecf8f33685c16d7c1198c"), + Id("21bd846065b322a450d8ecc20df022719a6ee9d27e6d718452e86737b11d8711"), + Id("f40e9eada23dd8b35639de13281ea29f1320e327397bd852a87c60e2c7db1617"), + Id("5c408cce16f21192cd257327c9cf35380fbc656528b3657f8f28b4f9c90bf7cb"), + Id("3c55d34e6e57083e654bfa03aaa6803b32901c71cd2402ec1fc10ebc827e0f11"), + Id("56a2ba4155aa9d6fdeb42243ed5555ef3093616f260d49deb373709e62f31eca"), + Id("5929a41f55203339259546ac63527c123caa64a6fb53dacfba9a706b7bef0dfa"), + Id("dbdd3103ddc402649e7875119f0eb9aa6f8cb3fc4d4d924dc5210173f9ca4c35"), + Id("3c27fc981259ade479111c4c26d35a91a0870526fb2fd7c20d5d5a510c4fc2f0"), + Id("01a8cb9bb17f736297f3f2d6c870c3c63aa518180f1f65793d56e993a39031ef"), + Id("694b5dc45c8cde02e68dbea363dc9f79fac38d9eb9866e68e10e3b7564d15750"), + Id("e303bf30b2e69d696de02c1fda859b752b540631b3c2cc4ff71e52130eae3f38"), + Id("f0ac70b5928ab7a20e7a2530622622d8613a0b3fe435d9e780e0a6a1ece9d0d5"), + Id("6612fd5528a16f9b662b98e4cf50c680b1217acf898d0879fbc28de188d77021"), + Id("83ef36236f6d526f0cd8d8a3df90e2520dc410d9263e68d2ef749387b995f4f3"), + Id("9ad82271530bbf463d8e4cf92884ee9e574ff28841e7d37c39af1807a1e90b12"), + Id("b4f8e4b9f046ca22f36b7dfea1539b710b6ff6012524b7ab9e1f5bf0dd2f658f"), + Id("c8ea8336d93e066470c4b85603b578846cfb3b7c11cceb42e01470d525005322"), + Id("69ca783c6554c3e94fcc70074f037ec483f6b89edf88c0f73f3ee87160d0d777"), + Id("cd3049b4967c028ae7459698cdc110cea7eb197c60d8a7488f2793a0f87a47d4"), + Id("7c4550e5767ded1e9a17745dc23d00ea849f4e4cc7461dc67a76333428fb8421"), + Id("50ec36b55a9b35de779a2757571d2e4b16f6d1ca3ff73ade120901262c2b265d"), + Id("2421b99b05d55dcd114fd59181c819c5c37169af6e96e1129cd957cc2440ba68"), + Id("ed86d1d05d6693df14f32e38a692cfac5634cc5b075fa2e7206d4fff9dd93d4f"), + Id("60c07c051e1fb8bf150472a6db5eac4b5528f9923154813782a6f4d7ccdfd400"), + Id("375c19e836d19c5a041dc320d5f04ad1f28dfca7a03215df67d16b842d20a9bd"), + Id("d47713d67818bc7bd404f2a09e66834e476659922ea8a906d3e7052afd19f96d"), + Id("b59026eea9ed5fc75014d241d92991d35110ae4e27bf4f9807a32553fd79b0fe"), + Id("b2ff0b767ddbe5da479f93fa3edc9d2bf7cdbc457d341f0bf3449d0c60013a93"), + Id("e27831ede4551c0943f9d6cdd93e77d659c32159fb3b2b754d0595535fbe8b9e"), + Id("2040dc10c41bb2ed5a97c32fd8d516c98eb3d72277a713778c386d96ad1c9651"), + Id("2e861f659fb6f91fc6cf4dbe42c681203cfa5297c2e29e94fae0872b216184f5"), + Id("0453c0a9bf04ca4aeb26ac01ca3d8ec1b66acb3f125e96369acf3334918beb42"), + Id("68e1a4420feff3b7fbfb7b179fc3bef12590a5b018cb15eb7e1fbd58fc26195c"), + Id("df399e97bb89d2a773cf90de0fc9499219598fb2d8f28c4269e6099372a7600d"), + Id("709aab191e613b202204613751615611035984128c8a4b7a50033a7b5a80b936"), + Id("39e85ed58a1ff03a9d340d18054e70961a5af0cf39dce2857488563804456f52"), + Id("488031128be5f4b7de5e2cec77fb6953f1f58affdf843d78753edb003d54f99a"), + Id("992bd2b1d097e0237b22adf3bf72b1d389212dd0e88251d3442e95c8aeed6803"), + Id("68212ec4e696bd4ae560965fe2bdadb7a446f14435a1f6a4c54c440518947ac9"), + Id("861da2970f4298b8d22f28b39f58811733f936838db50c4ddc099adc08a7e5f4"), + Id("f77e206f69693ae3490de38ce00f5e89ae7db4808b770c60e07d64815ee0478d"), + Id("ad980c1316495d55ed49233c8adeef7f31c50e3be033da73aba884c42de9a7c3"), + Id("e9d65ff27f350d46ab7b1147511723ad88a2453311ae209230072fa3ad7061b9"), + Id("b88bc214c913ba4fdb63b231d57ad302570e29a334620c9dbe6e633ccd80cdeb"), + Id("2aa3b00e3c5d28966714f16a8c9c249513bf5a33a6333f86f0fafb258f731a57"), + Id("cc0f1667d7f3c974ca07168ae76f5c0c12498a9927c4924b7a916e76d0d59423"), + Id("71fdec25b546a9547405ee4351e3024d58fa934ae14732f5141d3cc885f921b0"), + Id("704ff6c4917198e3cd3d3ecd8c8df9389b7771114b232709723e8900365be7f8"), + Id("6df5ac7a42c9d4573552c2a2e06ee5b9fe2726a0ab9789a296f38be2e0637954"), + Id("d6f9136327a02ad3f88efdacb5e04f837c3b89f5e2320256cbbcbb7e27ff9824"), + Id("25b85442540500c1542083649b882be38d47243b2a46d1b6be9b7a4866738a56"), + Id("44afd9cb3c5db29a93f383890875e92285d0e59da8eaf615bf1f344ebb3d1328"), + Id("6dff6740d3cd02cdb7e9c113e5d6e00210872393a5dfe4edb342ad91a149fc9f"), + Id("86cea31e56542428285073d70f3bb90c34be236188905e153e8a7852c36ecb8c"), + Id("4b573782c33b8b80f584b76ac8838b7f2171816f68ff7015ebdbe55fe7f08ec2"), + Id("074062c1c50304355040c1cfcc15524e915f0513b05452d5093c9161ca4b96fc"), + Id("9deebac846bf87eb7f22ff3dc58dc5672e40e207f5f9a4ba1b792914d745c71b"), + Id("a66ba27fec00140acc277c7e3b1a39710a9e57cc1c2ce3e25c7ed2d829d50711"), + Id("18e1e9407e32100f623b03264a0365bfc9247f92f63e9064102fca514f207dfb"), + Id("c24657d80d2b7c915ca6e31233bc79fbb70a3244211efb23654f491d9ab5cc80"), + Id("fe754e27836ebd4495f2d68820244ee6d47994aa2c86d98367f6dade359e6eda"), + Id("80c635089c5c158024ef40a7a609c670eb93b3e04226795130fc597c06c6ac0d"), + Id("8ba2cc8cf44054f35be413f12ba83969deb01f1c44660822cee1b960d69a7526"), + Id("ad072796b69d93f803061f2ec707686f4ca82b4b3ee02797b8d562d301bc5b20"), + Id("e12c60ddf8a985d80516a03818fb5d2183e6d5a0d07e8b893ace10c8fb976a89"), + Id("070bce68a9325cead2c3c33081e78cce983771bcbbe975ea7ea85107d28b4ed0"), + Id("f610a22d857b6284cb47dff861ab0d0d5229cba092e51f8b19eba3a40a172a56"), + Id("3b68340e037fd19fec46c5d192b39a0c59b9b1567de4c9e9b66de80ccd5142fc"), + Id("88adfa533864ba0c69dc3309b000018c3bd30af87f8e75820fe68478c1e4d314"), + Id("070be55ac7341b1684bcc0927ef90e53284788ea1f9481d01877a4c01ffe0cfb"), + Id("5a3ae6a849fd73e0d54a103a1cb0adc54aafc2321ffc546c131ce20cb12cf866"), + Id("0e2abf476fe5297b96932336e56e0d4fbc0e882aa74f910acca226e8eb6cf034"), + Id("d2bd6e102983c22aa6f74a749f40d13dfb311c464850a251f6b9f09d5f8974cb"), + Id("c2b0449d5cbfe62c95e9dab355ce0f8f98686d7224f8e69bc9b67aa01ff67beb"), + Id("e3724b3fbf1c02243e0c8839d7366b76c031c2f7c8d73e26cdd985471f055a4a"), + Id("81c218e8a1b61115ee49698454a771f3a7aa5b621419ce613e1ef0fa9db3d7e2"), + Id("6f72d513cb547f7b8c7336bfed8c0e96e28155c7799cfb10555fbd338874f7e5"), + Id("d77685c19e67a77ec844f74aeb3b0ec109b74daa3998f0328b288c8a9456849d"), + Id("d895a8c73c8d8acc4272dc5d091c1374a4a008522a886a851c4297993931dcc3"), + Id("16b50cf1782f265fbe9f6a062ef313de02b4ec7f3e3ddce212cb315f29d9b870"), + Id("35fb0a065bd90575a8bb3acd9b315f213bf0880a52888ef8f875847085ee3f7a"), + Id("d0e329dcb4e028cb84a4ac158197bd6572d7ee50350cbf96331b49d0355446e5"), + Id("66d2fb2381b231aa1d1925a14895c61e8dfbb84c7e54ad6887be7f75a63d9fc5"), + Id("5c448129d919722b8db49f903c80de709f0cab2ea6a2c1891779265da9a96734"), + Id("35b51f0b17e1b711ad929a8dba566220a2e0115cab97f93a73a925f3d42101aa"), + Id("551620b7abf7d0dd09e550eddd0e1d4c01832ac65cc40fc61612c61395e92fbd"), + Id("1db4e7abd8f7bac90caca9657fa131bbee769766f425a1db0ca6e9cb5b92adcc"), + Id("cd9383e2062c20a9c63de22e90d613b18a87340a269d428f3e6758ba34ece231"), + Id("3e26211a1a4e63cfaf22d5f3e4c87a0fdc521f177535620336301813d4a335b6"), + Id("45e5390b9c69e6368f06e3d21934d1579fe525c859cc1e7c6d3dd4796ee58a13"), + Id("c04eaece6815c7a325443a0d2c8c2b72c98a27e0deee06eeab78764602b764b0"), + Id("c896bed7b4b377d298c6ecaa8a6943524dfface02332561757ac2c39366f8411"), + Id("c6d8dc740588c48408942e8374a70685c2d00c3df4902c62ad80555fe4201616"), + Id("cfcca2fa0432f6723cddb9eb60e3a2734e9bf3c595440a6523e197b949b2043b"), + Id("b87fa4f136d32215f06636eccdd2e3fa719e563452c475897101b4689794cb1d"), + Id("d0d3e2c43fdb8e8580132b2fa525af6f9b3682846efc96f5299d2ee4bd7428be"), + Id("3948a73574045a786e326d9cb5fc91ee45994c1a2a0ebbd2fb9efd7ffc918599"), + Id("f6894be9bad47c1361b28672f69f565e4937cc2c43427185ac3fc17d6353b762"), + Id("30670463dbc57ef264fa168152c6951c27b000531b30f42dcd64e5fb7ce65377"), + Id("8d366f133601c8586d23289505d9a1b2267419cb4adc25c5995e57d0370cd762"), + Id("7862a9fce6492d2f9f8705ae5f5e29a09feb7b4a7d19f94837de57a5e4622164"), + Id("d1774b7bc459a572e27432935160b3a42c21e5dfb3d88fef264ee89f6546ef7d"), + Id("e6bae2c9c6b9d8b8a72b45590ffc6c8e034083d6a8180877f6d270537a1ac214"), + Id("83835133d61caa2cf9133a33f84329657f07d0122e552502db6a8047ba8478b0"), + Id("d1f516e645fb5dda4b6afa9eb83a1b28616d636d62b44c7db168d6d52c372f1e"), + Id("3971e462b0a9139e5f811f443529b3f50e1caaedfc5f27e69858f7ce972df0a4"), + Id("43d07cd468d71a348ab94a16a2da54186e352458002e0708fa28ed108129a316"), + Id("b0aa5dc32c279b4a9b0c026e41fe0925b12f70a32d3bb854110c16dcf70ae9c4"), + Id("94573e07d089c6e86f098887bdd0c89c860c138a3938bcb4f76e634cba025c5f"), + Id("e6d03c77b2ca3b90876b318a21be8f5dcfcaaaec33a726166d323a8d5381a23d"), + Id("9405dfd53d239334155c9886810dea644c6e03ae20b6335459c6d03164838b94"), + Id("85c8c1ab960e1197e918daf77d9b5e9331c3286dfd8602a3595b620330c98e6f"), + Id("f2d8744089a44ee800a088f5efc46bdbeed3461dce808de2a149c87cdcb7dc56"), + Id("198d4ce71d42827765fdab01f65f765469939fb7a14d172f70ec4b8927a18799"), + Id("32fb9db957fc10ac2812e9490533757f17602dc0f514e0ef7cd4d0a19645b6b6"), + Id("54959c4cf469742686d4ff82af7a4d2615dcccf5686f3778081b63ebe8b0fcba"), + Id("6a552bbb11485ea672ae6f66570b8dcac57051a636f6eacaefa18a76793eb19a"), + Id("a2458aeced2be4b4c2d18e188093c0e2cbf7f5bad0e40bc840e0eaec611fd7a8"), + Id("024231fd86e6efb1c99e802c92f664273faf99dca687cb452e0b1dc0f1739775"), + Id("8784733141b380be96d26c8cffaa077f338ce0dc72071fed8cf55b6e812c719a"), + Id("da6811cfc911962ccfa11b5c1b8e260a04f64fa981e5c69a66ab62636b0206a9"), + Id("8240255c22ead143cf731beaeb922e105fbb8d408046956994f5e167086b92d0"), + Id("db50526cf16a0a053a41f9b8c1c5c785832b3f0978201a9d334526fed36ce3db"), + Id("f53b922989ccc6656ac96019b18a8a11f067e97e938493549fc5f2db1f84cc84"), + Id("adf972f778d97c5b1cd00e2fe04954af594a64e7b8b018e7e572794a0c33f47f"), + Id("7bfadf58ab22fbecb871f3034bc7312b3ca14915ba825c41ce90f74ee57fa5cd"), + Id("55d2f4278ad11c8713274b81d88b60d06d625920360ffdf0e01523bdc52abb47"), + Id("5b298804fb688eb2f5f413e2990d21a64ecd6941fe9c0cb1ff622f3775c6eb82"), + Id("b983e631a900593b8cfbc90e856927ce020488a5e8670d217e5f730822b53d9d"), + Id("191104767f95246d3946f77375c17d692f55deeb8a61ca4d0483868b3aa0f807"), + Id("58d4a71822eb884b00a9f79344d365c84ef87d8a31d4fe2e1fd8191bdc88ec1f"), + Id("f91e85003da43bbf8f5efcd0cf4f84f3309e832cc78dabc9d2e47b5def73e197"), + Id("450290b4d8be35d70831cd8e2d959c0f6ab6753f422c69781655e3702e488280"), + Id("0d5117edd00e5f2766cad752db2af86766ad8dc3feb274ee6b9ca52f881d4e8f"), + Id("a076d1ad18af3963fc1c75333ff5b2ccb14459a994d24093a8ab10ad9d523890"), + Id("2b3ea52b1361b96442cd45a35adfe04435f630d2cafc1761d792ed1637d8fd6d"), + Id("d94d681704f2a591128a6abe756c98f0f5b98309d8f99f211c9f9350d87d812d"), + Id("6650577a245d17e07ad14bffbc398757052d5d60a1cc2cf188beed909ba8c988"), + Id("d31a5c649b7d8c21501cb288bc4850e0286a923e0ec3518b5d0030ea8d2ccf69"), + Id("626577d916fb14473bb1ff78f88fe05769510f253e44e5c6c37311d39fdf7e3c"), + Id("f5bc10c7c3d55cc4780c2e60543981ade73194b84c1a1bdbbcc88364f88d1965"), + Id("780773bc9fe9bacdc01573ff8f2fdc9519ac25d8d4b1d89f583e090b8b34e35e"), + Id("be2e0f8738b3d54bbd854c2f6bb1aec984dbe6ef94fedd21c2ce55ff64514419"), + Id("f879520cb3e653a0c77dcc37dcd813a71ec7d972a4a6185b13f2ed240c6e72e1"), + Id("178b49d00a00dab1be68d6b4464af35da0bbf3d770875a0f546375a302299a7b"), + Id("c6c794c54892db2441ed5ee4c715a8ee177e96241dfadbc359434c2b1e02de36"), + Id("c494106cd9e1a59343d12a2d8731de4f46dea7f2065f2ccd0c0c5bd13f138603"), + Id("d2d5c26249cf84a2822c710edfe0e9f10eeed8ae74cf318e0530f6cb08c51425"), + Id("2af638adc234b4f203259fc86b7aea026ff25e0b2869313b330b7a88ae2e5e9b"), + Id("1c0c331daae28c169e24b2c1c631f75fa1687acdc011590a2e0d955082f340f0"), + Id("9be1753f9a6eeab23c6c44dc8bdb44081ee82415d713fa9fc3b55316a0b380cc"), + Id("180abf4b8ed9e77578dbd2ade23c59ef7f9645b620e20f2714b5a6e8fe5924a7"), + Id("63530672cf882c7116525b4fc7d956576e68999411110f60fc261545a29b0b4d"), + Id("e7a1974951a8a5d1efe14dafc7634a265078c2e739e2d5dbffa0382a82bf061e"), + Id("1afe739c8f3703e6b2807107db592d0ef6269c43a44716e08f99311844904b87"), + Id("d7cf0ef60d82b2f3d2ba432448a997253e4fce8235f31a94a478fc5ae31b5c27"), + Id("3e4888164db11db1729beb2d7e3bfb0714dd7d79e1efd7a35cc29d9f4a1c6195"), + Id("d80f84ba6ac1d5976d79a0b12b10495dd81e83290ad743f1cf3530fda93d4175"), + Id("45b228d14bb8494ab2e37d39c7aa511bc23ccfb49bd9ea73843ecb0ed5a2a1e1"), + Id("c906750bc6fe5d788237fdf61565dc1d0bc95241ff62cc5f24c719f08775e460"), + Id("909c9adf869799f4b83eda97937f8f0d93c2ee32e8477d08e4e0be4eb7210342"), + Id("3ec7a00a519b3491e125b0b165b306b451a79d4ebc41af113eedbf0666ce78de"), + Id("d3abf8947a74dc248c35fa6c7fc2735015ae1fd1e4ed9e9ee05351396b0c47a5"), + Id("c5e260ccfa367b858e4596c8887b0ea7b6f1ce9b9364469469a3e271f90ab824"), + Id("d0e1a26f6e7d94826c2df6cd0df27f5df31f11a8ae31ce2f0c82186639daec6b"), + Id("03699920b5e9b041df3bf4d5d62bdd11e0b0420b0d956ffd7e2572b44e90a956"), + Id("3f470d4f8476541580d6291699610bef0ab32762628e6b921a206788b546b237"), + Id("4d3dee0ae9d3d46263a51783802c5ce8995261d03946ea8f556273b018393436"), + Id("89e8ce1ce1c56c7738fa0aa9129e315caf4b880184a023fdf601c1e873c325fc"), + Id("abdd324a27b5efa43951bb37018f9841e3f3ea356b9b019bdce3b41ae94396f8"), + Id("48d038ca22cf43d246f46572adae654f86c2a322d46bf85a9e85e3a297cf0c40"), + Id("2d370f7ed55ade23a4f328b33867673486da5fc7b42fb1bb61177890ad9aab8b"), + Id("51f9d4e517a7a1922ad127141fb1220befb12612c2bb4e6e014bf388a1762254"), + Id("17aba88676ec9ac0f9d9fb6b4554cb1790f7a553f56530d20c11809910fe5622"), + Id("1ed11e36b3171a187de0c459d2f4c250f449d8078bbd9b98db916701a10a216f"), + Id("1cb661234f72dab26c3ab4ac61721babd8f9f7c5e928880d367fcff8ca8f9737"), + Id("7c7bd251ef693969ab5e204cfdffb5574ad5663bf2e62bc318cbfbdca8c0ac9b"), + Id("8f10cf59382e40e1fb7721390df9b52ab00d572a0cb2bfc12764f4ad340b1865"), + Id("93fb7972041a5e278681fc35dc0587a935056c34d1c25c24a1b7239d45961fb8"), + Id("a67a7a9312e2ab84a77269056075042b2f43e9d48d5a984f715570b71057ee3e"), + Id("c9f45e4fa87770f0d9abba5cfa6853945c0601808a9b17ee3e0777369c3053ae"), + Id("e2f715f24bd96a54aa7343e89cdce44ec0991284fd4564282e23c08944b10dda"), + Id("c8a36a852050367f66ea318ce3a11243b521c6ea36a6eeb71c43580b0952e740"), + Id("34718bd31b0a8139fce6e3e6addd62d5e2ae7689ff658e6223ea0bfc8366f4ee"), + Id("3e8a0d41046f8f766ab9220ffb79e61d6ec529b621e994c9b17695b352ce30b5"), + Id("6a382e393b9704ee224893ef9fcef0552f2e13dfebdd9bdebac060d07f086d62"), + Id("9f5580a0f88f1bd31c851547e153ff88c2f379657a26f7e41c8da8dfdf90935e"), + Id("d648d73cac8046adb57ddae94bfcd17776546d97d3e6252bf5b8b6e78d0e549f"), + Id("6662504204c5d17802aade9155b58989d8c79418769c12545003fbd3c7d9915d"), + Id("63b291e27f66a659caaad0eb39770bbee423f2a2a0ca9d3b57b1563e8145e1ca"), + Id("145fba497fe42b1aaa18194762b9ed482eca73d773331938d3b4e963f3e205dc"), + Id("0aecc98eb1e9c7ab4a04a0fa3dbc86ac17f7448e05bdab4f59f2761b86ed5e9c"), + Id("32b962e00b1c76ba4b210bc001ce112297f27574121191d9e06dc3e30eadbf27"), + Id("339320526e11c08966f18322109ddd576e0fa0b10dc310d456dd53662f4247f6"), + Id("e7faba6d8d8d1dcd6bc0a1ddab282c2584c18400ad281e543370c3bcc1bfebc1"), + Id("9b6c160c6b88771032a1b2365156dd03bc14b79ba1ec63213760f15750a6d5e8"), + Id("fbc1f4fb848bdc39645e734203921b320baae25ff12a280fc46700a79bcdc0cd"), + Id("f44531fabe46ad56339ac7f02c6521c01906572ca3f22875fc906e22c9041365"), + Id("c62ef0f5bbe106b11fa75dbb538e357c56d879578b973ca408d7060c277d7774"), + Id("f2ab4363b19a78f868cb4fabcda8245e1a4ba6b5c37a185fdc17e8415d46ccb2"), + Id("817a281fa47749a849d60eee6d404c5d0aaff448159c61e42e7a0362a3aeb61e"), + Id("b53d3c0f6e3a43c9cf35c68831079d4ad3043354558d52f9941a9c1dafcb86f7"), + Id("e33ab3e600aa59011ac1d1d159b61b445b8dfea15dc607c450992c6ebe3a8e5f"), + Id("1e753384c559f1d873130ecdcef21030d3909dc1574a0104e36b564d6fec1426"), + Id("ae559b912ba885f881ec03bed75747ecff9599d1919adb2f58905a0e2b5a3f9b"), + Id("0e9a171cfc615d186ceac796f3e42f9de3ddb48bb60d5b7ae5e80d0927e1fd6f"), + Id("7f48465a6e3b0a1486df513595d6dff4ef63b4d1ed9b2600ac3a897211c30ac2"), + Id("3c41b811c8659312a1bd525d88da1ee47579c1ad00c0fc8369cb95b88e318007"), + Id("aaa1fa0c8a846955f4d3e5f659de9c6883b2eb0ff01a3f3d21ea0eb56427ffaa"), + Id("0bc1f65e245a4716b44b80f79fe66af53caf1625ec57d94ed063411f04fef7f4"), + Id("84dc826be3bbc1c82761f2c311ddce115267b08bb6a289efb38494538f303548"), + Id("57e3f93b1ac0928db8a55e77824e043bcf25ee28bfed1e60aaa9d568dd79e574"), + Id("49940c21180815deccecaad0f7d9f3114edcef219d889c38657ce88286309f71"), + Id("d85b2a6aabc8a65a6d4e0fadeab4a0efced336f247f020d34b404bf0d42f38be"), + Id("a39e69f47f6617866beeff292c25613aa4776abe8f11108035fa38bc72030c59"), + Id("4cef75f0d1b85366dae6f20743ee4ed5680ad02abbf1f545f740f433b59c4397"), + Id("6406a2538fe8c6e8d5542c05411b4f030047ce0addb1d1f853779931fd0bb576"), + Id("66d1f268fedfbef3a93cb1b38afbfd9428bc6ba4c3f5ccb5fc26dbcc1aa33baf"), + Id("2bfb678e1f9636e67e5f3f6086cc1aff6da99ce67d129b57c5b3f33afebf1b86"), + Id("a4ecb98fd0edc74f26c35a092f11fd07c4d5ff42e31150f4fea57ac3f9dc162a"), + Id("c7b8c4c7f1906cdaf578c0b49f31c8258f103cacc1b54c746f5c11ad0fa45a65"), + Id("938da50af3f79bcf1838338370fab3528e25737cb87ef6d6ae66e0916d175f8f"), + Id("335631183ce61201130ea8d1657b7f6aa2b1d7843ceb1eee09991d65955f5a21"), + Id("48b63b241cfe3a12114128bdc58bff7b7b07e4e1a37ae18cd904cd8ba8dbfd5e"), + Id("6977dade4ea4ff6cc2c6003aa7465d3ffe111bc8fdb62e9a20aa133542bc20d6"), + Id("02fc0ef80695a4bb7b7db02d80997dd16f0ed063b58e94b4700610151de166d2"), + Id("2dae514a1777cf8ac5d78402af32234ee60e53bf1e69eb2214831d7b3a576829"), + Id("bcc0e6e360e1d6e0cad4a1af4bdeae444ffe0108bceefae8d2e651db66694b1a"), + Id("4ad8632c383835ccc5cd95b09cc22cd57bb999fc17b85e3c061034d3833f798d"), + Id("53e37eaa5afcb9f1a025790e9b0df1ec1b347bcab631a5db17c04c7fe5c07a5a"), + Id("7112f32a249a72883663a3c52a6c49b46429c5e5aae9e400e7e2d7aaba2ae828"), + Id("d07f392b1dfebfdf50bb10a4a7857b543cbe246f84549af8902dfde9737fd425"), + Id("fb1d2cf766f42c1c36a3395b5156f9e1e36942f38e40f15534b42082cb5d7329"), + Id("6ed7a1b304be0dc50f29f58897bb874fe53b5a625ab433674b0e0727a70b13e8"), + Id("2ccf3c05cd3c83621992b2f804fde3a1d7b2cf159423fe4dab2b6d2dfe3e7650"), + Id("a4b091b8c75fe115154e9b87451999bf01419e52a813f513d22eb8638d450fc4"), + Id("1a7804d8f4c14be0de7c7972687d7cc8e3df0532028448bc5458aec4489a9730"), + Id("4c01d8b67d5650e558ba4983e1784d9e1ee466ba41a79d67f11a67c5ec97fd3c"), + Id("8b7fda87a507a149b54be007efd819731b5ffa8a3854113b430af7ac64814a11"), + Id("255d2a4fbbbbd47d585e5515f3f9b60376970bbc692592d57d4827949b99537f"), + Id("a6712e93ecb2fb8a83c703c570f3e21af28c68d945c621ddb3897abcb1192fad"), + Id("eb3419fe1265c2796ad1b8b1838025d1e410b124e7e7b7feca6d1e2d9566449e"), + Id("e6af7c34c1d5d0722ab9f1699439e512b1f95f8d628b9eada9e72974af578a5c"), + Id("cd10ef439ed00c7b3ab758d35195d2ec87eb2465c7dc8efc4ecccf8bdb7aa12a"), + Id("f828044ab32df44b1edcf72499d45d2717a135a606241ae08cbd862bf884d6bc"), + Id("43b7a1ce1f048541e9b03e9ab39a38e4ffd5330a336769b0b59f81026d489e6e"), + Id("4c312448826cfffebd993619e83d4a163303bfa9f5819d4318475e0166ece22c"), + Id("3e5fc14a65b5de6a5b9c46cba14754867d729197329374015d2fc9717ad136a3"), + Id("f58b783a5bf10e92d772bb975aa53efd1c73b97b9ada5127d4c419061f4bf0c2"), + Id("1bb89a9168761e0b8e59ab23820cf348ead199999943f408d22aaa01fa23e836"), + Id("d98c82500978ae7778e5cd0d2156e69a70799f4d023f4ac0335eaba729c2a390"), + Id("23b1da2215e17c37d438a97d43def9879d538d2f07a165bafda1d738d51722eb"), + Id("6d363e38a62a8ad3937357ae55057afd7edc5912ac840842145f3a43b07fdd75"), + Id("069df78d3a7f51f0171a9d64ed58c1728fc0f86fe725680d920ffb384d0068bd"), + Id("213d4565ca5161123aec22060b362fc6188e2ee41c11df09e5db868050c251bd"), +] diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index ef15e441..8c6c0967 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -8,7 +8,7 @@ use std::{ error::Error, ffi::OsString, - num::{ParseIntError, TryFromIntError}, + num::{ParseFloatError, ParseIntError, TryFromIntError}, ops::RangeInclusive, path::{PathBuf, StripPrefixError}, process::ExitStatus, @@ -186,6 +186,8 @@ pub enum CommandErrorKind { /// pack {0} got no decision what to do NoDecision(PackId), /// {0:?} + FromParseFloatError(#[from] ParseFloatError), + /// {0:?} FromParseIntError(#[from] ParseIntError), /// {0} FromByteSizeParser(String), diff --git a/crates/core/src/id.rs b/crates/core/src/id.rs index 6b19560c..9fd2d3a5 100644 --- a/crates/core/src/id.rs +++ b/crates/core/src/id.rs @@ -5,6 +5,7 @@ use std::{fmt, io::Read, ops::Deref, path::Path, str::FromStr}; use binrw::{BinRead, BinWrite}; use derive_more::{Constructor, Display}; use rand::{thread_rng, RngCore}; +use safe_transmute::{transmute_one, TriviallyTransmutable}; use serde_derive::{Deserialize, Serialize}; use crate::{crypto::hasher::hash, error::IdErrorKind, RusticError, RusticResult}; @@ -108,12 +109,18 @@ impl Id { /// Generate a random `Id`. #[must_use] - pub fn random() -> Self { + pub fn random_from_rng(rng: &mut impl RngCore) -> Self { let mut id = Self::default(); - thread_rng().fill_bytes(&mut id.0); + rng.fill_bytes(&mut id.0); id } + /// Generate a random `Id`. + #[must_use] + pub fn random() -> Self { + Self::random_from_rng(&mut thread_rng()) + } + /// Convert to [`HexId`]. /// /// # Examples @@ -169,6 +176,10 @@ impl Id { let mut vec = vec![0; length]; r.read_exact(&mut vec).is_ok() && self == &hash(&vec) } + + pub(crate) fn transmute(&self) -> T { + transmute_one(&self.0).unwrap() + } } impl fmt::Debug for Id { diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 1024f30a..e6740500 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -135,7 +135,7 @@ pub use crate::{ }, commands::{ backup::{BackupOptions, ParentOptions}, - check::CheckOptions, + check::{CheckOptions, ReadSubsetOption}, config::ConfigOptions, copy::CopySnapshot, forget::{ForgetGroup, ForgetGroups, ForgetSnapshot, KeepOptions}, diff --git a/crates/core/src/repository.rs b/crates/core/src/repository.rs index e4d52265..eb40959f 100644 --- a/crates/core/src/repository.rs +++ b/crates/core/src/repository.rs @@ -1079,7 +1079,7 @@ impl Repository { Ok(()) } - /// Check the repository for errors or inconsistencies + /// Check the repository and all snapshot trees for errors or inconsistencies /// /// # Arguments /// @@ -1089,7 +1089,26 @@ impl Repository { /// // TODO: Document errors pub fn check(&self, opts: CheckOptions) -> RusticResult<()> { - opts.run(self) + let trees = self + .get_all_snapshots()? + .into_iter() + .map(|snap| snap.tree) + .collect(); + + opts.run(self, trees) + } + + /// Check the repository and given trees for errors or inconsistencies + /// + /// # Arguments + /// + /// * `opts` - The options to use + /// + /// # Errors + /// + // TODO: Document errors + pub fn check_with_trees(&self, opts: CheckOptions, trees: Vec) -> RusticResult<()> { + opts.run(self, trees) } /// Get the plan about what should be pruned and/or repacked.