diff --git a/Cargo.lock b/Cargo.lock index 03d40dcef7..c49f58b71c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5219,30 +5219,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "solana-stake-o-matic" -version = "1.7.0" -dependencies = [ - "clap", - "log 0.4.11", - "reqwest", - "semver 0.9.0", - "serde", - "serde_json", - "serde_yaml", - "solana-clap-utils", - "solana-cli-config", - "solana-cli-output", - "solana-client", - "solana-logger 1.7.0", - "solana-metrics", - "solana-notifier", - "solana-sdk", - "solana-stake-program", - "solana-transaction-status", - "thiserror", -] - [[package]] name = "solana-stake-program" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index de0d0a5070..0d21b9424b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,6 @@ members = [ "log-analyzer", "merkle-root-bench", "merkle-tree", - "stake-o-matic", "storage-bigtable", "storage-proto", "streamer", diff --git a/scripts/cargo-install-all.sh b/scripts/cargo-install-all.sh index 1352471c4e..f86961d11a 100755 --- a/scripts/cargo-install-all.sh +++ b/scripts/cargo-install-all.sh @@ -95,7 +95,6 @@ else solana-net-shaper solana-stake-accounts solana-stake-monitor - solana-stake-o-matic solana-sys-tuner solana-test-validator solana-tokens diff --git a/stake-o-matic/.gitignore b/stake-o-matic/.gitignore deleted file mode 100644 index f519667a5c..0000000000 --- a/stake-o-matic/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target/ -solana-install/ diff --git a/stake-o-matic/Cargo.toml b/stake-o-matic/Cargo.toml deleted file mode 100644 index fe185e1b3b..0000000000 --- a/stake-o-matic/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -authors = ["Solana Maintainers "] -description = "I will find you and I will stake you" -edition = "2018" -homepage = "https://solana.com/" -documentation = "https://docs.rs/" -license = "Apache-2.0" -name = "solana-stake-o-matic" -repository = "https://github.com/solana-labs/stake-o-matic" -version = "1.7.0" - -[dependencies] -clap = "2.33.0" -log = "0.4.11" -reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] } -semver = "0.9.0" -serde = { version = "1.0.122", features = ["derive"] } -serde_json = "1.0.62" -serde_yaml = "0.8.13" -solana-clap-utils = { path = "../clap-utils", version = "=1.7.0" } -solana-client = { path = "../client", version = "=1.7.0" } -solana-cli-config = { path = "../cli-config", version = "=1.7.0" } -solana-cli-output = { path = "../cli-output", version = "=1.7.0" } -solana-logger = { path = "../logger", version = "=1.7.0" } -solana-metrics = { path = "../metrics", version = "=1.7.0" } -solana-notifier = { path = "../notifier", version = "=1.7.0" } -solana-sdk = { path = "../sdk", version = "=1.7.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.7.0" } -solana-transaction-status = { path = "../transaction-status", version = "=1.7.0" } -thiserror = "1.0.21" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/stake-o-matic/README.md b/stake-o-matic/README.md deleted file mode 100644 index b68b148455..0000000000 --- a/stake-o-matic/README.md +++ /dev/null @@ -1,21 +0,0 @@ -## Effortlessly Manage Cluster Stakes -The testnet and mainnet-beta clusters currently have a large population of -validators that need to be staked by a central authority. - -## Staking Criteria -1. All non-delinquent validators receive 50,000 SOL stake -1. Additionally, non-deliquent validators that have produced a block in 75% of - their slots in the previous epoch receive bonus stake of 500,000 SOL - -A validator that is delinquent for more than 24 hours will have all stake -removed. However stake-o-matic has no memory, so if the same validator resolves -their delinquency then they will be re-staked again - -## Validator Whitelist -To be eligible for staking, a validator's identity pubkey must be added to a -YAML whitelist file. - -## Stake Account Management -Stake-o-matic will split the individual validator stake accounts from a master -stake account, and must be given the authorized staker keypair for the master -stake account. diff --git a/stake-o-matic/src/confirmed_block_cache.rs b/stake-o-matic/src/confirmed_block_cache.rs deleted file mode 100644 index aed22fcca9..0000000000 --- a/stake-o-matic/src/confirmed_block_cache.rs +++ /dev/null @@ -1,248 +0,0 @@ -use crate::retry_rpc_operation; -use log::*; -use serde::{Deserialize, Serialize}; -use solana_client::rpc_client::RpcClient; -use solana_sdk::{ - clock::{Slot, DEFAULT_SLOTS_PER_EPOCH}, - commitment_config::CommitmentConfig, - epoch_info::EpochInfo, -}; -use std::{ - cell::RefCell, - fs::{self, File, OpenOptions}, - io, - ops::Range, - path::{Path, PathBuf}, -}; - -#[derive(Clone, Debug, Default)] -struct Entry { - slots: Range, - path: PathBuf, -} - -impl Entry { - pub fn new>(base_path: P, slots: Range) -> Self { - let file_name = format!("{}-{}.json", slots.start, slots.end); - let path = base_path.as_ref().join(file_name); - Self { slots, path } - } - - fn parse_filename>(filename: F) -> Option> { - let filename = filename.as_ref(); - let slot_range = filename.file_stem(); - let extension = filename.extension(); - extension - .zip(slot_range) - .and_then(|(extension, slot_range)| { - if extension == "json" { - slot_range.to_str() - } else { - None - } - }) - .and_then(|slot_range| { - let mut parts = slot_range.splitn(2, '-'); - let start = parts.next().and_then(|p| p.parse::().ok()); - let end = parts.next().and_then(|p| p.parse::().ok()); - start.zip(end).map(|(start, end)| start..end) - }) - } - - pub fn from_pathbuf(path: PathBuf) -> Option { - path.file_name() - .and_then(|n| n.to_str()) - .and_then(Self::parse_filename) - .map(|slots| Self { slots, path }) - } - - pub fn path(&self) -> &Path { - &self.path - } -} - -const CACHE_VERSION: u64 = 0; -const DEFAULT_SLOTS_PER_ENTRY: u64 = 2500; -const DEFAULT_MAX_CACHED_SLOTS: u64 = 5 * DEFAULT_SLOTS_PER_EPOCH; -const CONFIG_FILENAME: &str = "config.yaml"; - -#[derive(Debug, Deserialize, Serialize)] -struct Config { - version: u64, - slots_per_chunk: u64, - max_cached_slots: u64, -} - -impl Default for Config { - fn default() -> Self { - Self { - version: CACHE_VERSION, - slots_per_chunk: DEFAULT_SLOTS_PER_ENTRY, - max_cached_slots: DEFAULT_MAX_CACHED_SLOTS, - } - } -} - -pub struct ConfirmedBlockCache { - rpc_client: RpcClient, - base_path: PathBuf, - entries: RefCell>, - config: Config, -} - -impl ConfirmedBlockCache { - fn store_config>(config_path: P, config: &Config) -> io::Result<()> { - let config_path = config_path.as_ref(); - let file = File::create(config_path)?; - serde_yaml::to_writer(file, config).map_err(|e| { - io::Error::new( - io::ErrorKind::Other, - format!( - "error: cannot store config `{}`: {:?}", - config_path.to_string_lossy(), - e, - ), - ) - }) - } - - fn load_config>(config_path: P) -> io::Result { - let config_path = config_path.as_ref(); - let file = File::open(config_path)?; - serde_yaml::from_reader(file).map_err(|e| { - io::Error::new( - io::ErrorKind::Other, - format!( - "error: cannot load config `{}`: {:?}", - config_path.to_string_lossy(), - e, - ), - ) - }) - } - - pub fn open, U: AsRef>(path: P, rpc_url: U) -> io::Result { - let path = path.as_ref(); - let config_path = path.join(CONFIG_FILENAME); - let rpc_url = rpc_url.as_ref(); - let rpc_client = RpcClient::new(rpc_url.to_string()); - let (config, entries) = match fs::read_dir(path) { - Ok(dir_entries) => { - let config = Self::load_config(&config_path)?; - if config.version != CACHE_VERSION { - return Err(io::Error::new( - io::ErrorKind::Other, - "unexpected cache version", - )); - } - let current_slot = rpc_client - .get_slot() - .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e)))?; - let eviction_slot = current_slot.saturating_sub(config.max_cached_slots); - let (delete, mut entries) = dir_entries - .filter_map(|de| Entry::from_pathbuf(de.unwrap().path())) - .fold( - (Vec::new(), Vec::new()), - |(mut delete, mut entries), entry| { - if entry.slots.end < eviction_slot { - delete.push(entry); - } else { - entries.push(entry); - } - (delete, entries) - }, - ); - let mut evicted_ranges = Vec::new(); - for d in &delete { - match std::fs::remove_file(&d.path) { - Ok(()) => evicted_ranges.push(format!("{:?}", d.slots)), - Err(e) => warn!("entry eviction for slots {:?} failed: {}", d.slots, e), - } - } - debug!("entries evicted for slots: {}", evicted_ranges.join(", ")); - entries.sort_by(|l, r| l.slots.start.cmp(&r.slots.start)); - Ok((config, entries)) - } - Err(err) => { - if err.kind() == io::ErrorKind::NotFound { - let config = Config::default(); - fs::create_dir_all(path)?; - Self::store_config(config_path, &config)?; - Ok((config, Vec::new())) - } else { - Err(err) - } - } - }?; - Ok(Self { - rpc_client, - base_path: path.to_path_buf(), - entries: RefCell::new(entries), - config, - }) - } - - fn lookup(&self, start: Slot) -> Option { - let entries = self.entries.borrow(); - for i in entries.iter() { - if i.slots.start == start { - debug!("HIT: {}", start); - return Some(i.clone()); - } - } - debug!("MISS: {}", start); - None - } - - fn fetch(&self, start: Slot, end: Slot, epoch_info: &EpochInfo) -> io::Result> { - debug!("fetching slot range: {}..{}", start, end); - // Fingers crossed we hit the same RPC backend... - let slots = retry_rpc_operation(42, || { - self.rpc_client.get_confirmed_blocks(start, Some(end)) - }) - .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))?; - - // Only cache complete chunks - if end + self.config.slots_per_chunk < epoch_info.absolute_slot { - debug!("committing entry for slots {}..{}", start, end); - let entry = Entry::new(&self.base_path, start..end); - let file = OpenOptions::new() - .write(true) - .create_new(true) - .open(entry.path())?; - serde_json::to_writer(file, &slots)?; - - self.entries.borrow_mut().push(entry); - } - - Ok(slots) - } - - pub fn query(&self, start: Slot, end: Slot) -> io::Result> { - let chunk_size = self.config.slots_per_chunk; - let mut chunk_start = (start / chunk_size) * chunk_size; - let mut slots = Vec::new(); - let epoch_info = self - .rpc_client - .get_epoch_info_with_commitment(CommitmentConfig::finalized()) - .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))?; - let last_slot = end.min(epoch_info.absolute_slot); - while chunk_start < last_slot { - let mut chunk_slots = if let Some(entry) = self.lookup(chunk_start) { - let file = File::open(entry.path())?; - serde_json::from_reader(file)? - } else { - let chunk_end = chunk_start + chunk_size - 1; - self.fetch(chunk_start, chunk_end, &epoch_info)? - }; - slots.append(&mut chunk_slots); - chunk_start += chunk_size; - } - let slots = slots - .drain(..) - .skip_while(|s| *s < start) - .take_while(|s| *s <= end) - .collect::>(); - Ok(slots) - } -} diff --git a/stake-o-matic/src/main.rs b/stake-o-matic/src/main.rs deleted file mode 100644 index 6a89d9ca7c..0000000000 --- a/stake-o-matic/src/main.rs +++ /dev/null @@ -1,1718 +0,0 @@ -#![allow(clippy::integer_arithmetic)] -use { - clap::{ - crate_description, crate_name, crate_version, value_t, value_t_or_exit, App, Arg, - ArgMatches, - }, - log::*, - reqwest::StatusCode, - solana_clap_utils::{ - input_parsers::{keypair_of, pubkey_of}, - input_validators::{ - is_amount, is_keypair, is_pubkey_or_keypair, is_url, is_valid_percentage, - }, - }, - solana_cli_output::display::format_labeled_address, - solana_client::{ - client_error, rpc_client::RpcClient, rpc_config::RpcSimulateTransactionConfig, - rpc_request::MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS, rpc_response::RpcVoteAccountInfo, - }, - solana_metrics::datapoint_info, - solana_notifier::Notifier, - solana_sdk::{ - account_utils::StateMut, - clock::{Epoch, Slot}, - commitment_config::CommitmentConfig, - message::Message, - native_token::*, - pubkey::Pubkey, - signature::{Keypair, Signature, Signer}, - transaction::Transaction, - }, - solana_stake_program::{stake_instruction, stake_state::StakeState}, - std::{ - collections::{HashMap, HashSet}, - error, - fs::File, - path::PathBuf, - process, - str::FromStr, - thread::sleep, - time::Duration, - }, - thiserror::Error, -}; - -mod confirmed_block_cache; -mod validator_list; -mod validators_app; - -use confirmed_block_cache::ConfirmedBlockCache; - -enum InfrastructureConcentrationAffectKind { - Destake(String), - Warn(String), -} - -#[derive(Debug)] -enum InfrastructureConcentrationAffects { - WarnAll, - DestakeListed(HashSet), - DestakeAll, -} - -impl InfrastructureConcentrationAffects { - fn destake_memo(validator_id: &Pubkey, concentration: f64, config: &Config) -> String { - format!( - "🏟️ `{}` infrastructure concentration {:.1}% is too high. Max concentration is {:.0}%. Removed ◎{}", - validator_id, - concentration, - config.max_infrastructure_concentration, - lamports_to_sol(config.baseline_stake_amount), - ) - } - fn warning_memo(validator_id: &Pubkey, concentration: f64, config: &Config) -> String { - format!( - "🗺 `{}` infrastructure concentration {:.1}% is too high. Max concentration is {:.0}%. No stake removed. Consider finding a new data center", - validator_id, - concentration, - config.max_infrastructure_concentration, - ) - } - pub fn memo( - &self, - validator_id: &Pubkey, - concentration: f64, - config: &Config, - ) -> InfrastructureConcentrationAffectKind { - match self { - Self::DestakeAll => InfrastructureConcentrationAffectKind::Destake(Self::destake_memo( - validator_id, - concentration, - config, - )), - Self::WarnAll => InfrastructureConcentrationAffectKind::Warn(Self::warning_memo( - validator_id, - concentration, - config, - )), - Self::DestakeListed(ref list) => { - if list.contains(validator_id) { - InfrastructureConcentrationAffectKind::Destake(Self::destake_memo( - validator_id, - concentration, - config, - )) - } else { - InfrastructureConcentrationAffectKind::Warn(Self::warning_memo( - validator_id, - concentration, - config, - )) - } - } - } - } -} - -#[derive(Debug, Error)] -#[error("cannot convert to InfrastructureConcentrationAffects: {0}")] -struct InfrastructureConcentrationAffectsFromStrError(String); - -impl FromStr for InfrastructureConcentrationAffects { - type Err = InfrastructureConcentrationAffectsFromStrError; - fn from_str(s: &str) -> Result { - let lower = s.to_ascii_lowercase(); - match lower.as_str() { - "warn" => Ok(Self::WarnAll), - "destake" => Ok(Self::DestakeAll), - _ => { - let file = File::open(s) - .map_err(|_| InfrastructureConcentrationAffectsFromStrError(s.to_string()))?; - let mut list: Vec = serde_yaml::from_reader(file) - .map_err(|_| InfrastructureConcentrationAffectsFromStrError(s.to_string()))?; - let list = list - .drain(..) - .filter_map(|ref s| Pubkey::from_str(s).ok()) - .collect::>(); - Ok(Self::DestakeListed(list)) - } - } - } -} - -pub fn is_release_version(string: String) -> Result<(), String> { - if string.starts_with('v') && semver::Version::parse(string.split_at(1).1).is_ok() { - return Ok(()); - } - semver::Version::parse(&string) - .map(|_| ()) - .map_err(|err| format!("{:?}", err)) -} - -pub fn release_version_of(matches: &ArgMatches<'_>, name: &str) -> Option { - matches - .value_of(name) - .map(ToString::to_string) - .map(|string| { - if string.starts_with('v') { - semver::Version::parse(string.split_at(1).1) - } else { - semver::Version::parse(&string) - } - .expect("semver::Version") - }) -} - -#[derive(Debug)] -struct Config { - json_rpc_url: String, - cluster: String, - source_stake_address: Pubkey, - authorized_staker: Keypair, - - /// Only validators with an identity pubkey in this validator_list will be staked - validator_list: HashSet, - - dry_run: bool, - - /// Amount of lamports to stake any validator in the validator_list that is not delinquent - baseline_stake_amount: u64, - - /// Amount of additional lamports to stake quality block producers in the validator_list - bonus_stake_amount: u64, - - /// Quality validators produce within this percentage of the cluster average skip rate over - /// the previous epoch - quality_block_producer_percentage: usize, - - /// A delinquent validator gets this number of slots of grace (from the current slot) before it - /// will be fully destaked. The grace period is intended to account for unexpected bugs that - /// cause a validator to go down - delinquent_grace_slot_distance: u64, - - /// Don't ever unstake more than this percentage of the cluster at one time for poor block - /// production - max_poor_block_producer_percentage: usize, - - /// Vote accounts with a larger commission than this amount will not be staked. - max_commission: u8, - - address_labels: HashMap, - - /// If Some(), destake validators with a version less than this version subject to the - /// `max_old_release_version_percentage` limit - min_release_version: Option, - - /// Don't ever unstake more than this percentage of the cluster at one time for running an - /// older software version - max_old_release_version_percentage: usize, - - /// Base path of confirmed block cache - confirmed_block_cache_path: PathBuf, - - /// Vote accounts sharing infrastructure with larger than this amount will not be staked - max_infrastructure_concentration: f64, - - /// How validators with infrastruction concentration above `max_infrastructure_concentration` - /// will be affected. Accepted values are: - /// 1) "warn" - Stake unaffected. A warning message is notified - /// 2) "destake" - Removes all validator stake - /// 3) PATH_TO_YAML - Reads a list of validator identity pubkeys from the specified YAML file - /// destaking those in the list and warning any others - infrastructure_concentration_affects: InfrastructureConcentrationAffects, - - /// Use a cluster-average skip rate floor for block-production quality calculations - use_cluster_average_skip_rate: bool, - - bad_cluster_average_skip_rate: usize, -} - -impl Config { - #[cfg(test)] - pub fn default_for_test() -> Self { - Self { - json_rpc_url: "https://api.mainnet-beta.com".to_string(), - cluster: "mainnet-beta".to_string(), - source_stake_address: Pubkey::new_unique(), - authorized_staker: Keypair::new(), - validator_list: HashSet::default(), - dry_run: true, - baseline_stake_amount: 25_000, - bonus_stake_amount: 175_000, - quality_block_producer_percentage: 15, - delinquent_grace_slot_distance: 21_600, - max_poor_block_producer_percentage: 20, - max_commission: 100, - address_labels: HashMap::default(), - min_release_version: None, - max_old_release_version_percentage: 10, - confirmed_block_cache_path: default_confirmed_block_cache_path(), - max_infrastructure_concentration: 100.0, - infrastructure_concentration_affects: InfrastructureConcentrationAffects::WarnAll, - use_cluster_average_skip_rate: false, - bad_cluster_average_skip_rate: 50, - } - } -} - -fn default_confirmed_block_cache_path() -> PathBuf { - let home_dir = std::env::var("HOME").unwrap(); - PathBuf::from(home_dir).join(".cache/solana/som/confirmed-block-cache/") -} - -fn get_config() -> Config { - let default_confirmed_block_cache_path = default_confirmed_block_cache_path() - .to_str() - .unwrap() - .to_string(); - let matches = App::new(crate_name!()) - .about(crate_description!()) - .version(crate_version!()) - .arg({ - let arg = Arg::with_name("config_file") - .short("C") - .long("config") - .value_name("PATH") - .takes_value(true) - .global(true) - .help("Configuration file to use"); - if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { - arg.default_value(&config_file) - } else { - arg - } - }) - .arg( - Arg::with_name("json_rpc_url") - .long("url") - .value_name("URL") - .takes_value(true) - .validator(is_url) - .help("JSON RPC URL for the cluster") - ) - .arg( - Arg::with_name("cluster") - .long("cluster") - .value_name("NAME") - .possible_values(&["mainnet-beta", "testnet"]) - .takes_value(true) - .help("Name of the cluster to operate on") - ) - .arg( - Arg::with_name("validator_list_file") - .long("validator-list") - .value_name("FILE") - .required(true) - .takes_value(true) - .conflicts_with("cluster") - .help("File containing an YAML array of validator pubkeys eligible for staking") - ) - .arg( - Arg::with_name("confirm") - .long("confirm") - .takes_value(false) - .help("Confirm that the stake adjustments should actually be made") - ) - .arg( - Arg::with_name("source_stake_address") - .index(1) - .value_name("ADDRESS") - .takes_value(true) - .required(true) - .validator(is_pubkey_or_keypair) - .help("The source stake account for splitting individual validator stake accounts from") - ) - .arg( - Arg::with_name("authorized_staker") - .index(2) - .value_name("KEYPAIR") - .validator(is_keypair) - .required(true) - .takes_value(true) - .help("Keypair of the authorized staker for the source stake account.") - ) - .arg( - Arg::with_name("quality_block_producer_percentage") - .long("quality-block-producer-percentage") - .value_name("PERCENTAGE") - .takes_value(true) - .default_value("15") - .validator(is_valid_percentage) - .help("Quality validators have a skip rate within this percentage of the cluster average in the previous epoch.") - ) - .arg( - Arg::with_name("bad_cluster_average_skip_rate") - .long("bad-cluster-average-skip-rate") - .value_name("PERCENTAGE") - .takes_value(true) - .default_value("50") - .validator(is_valid_percentage) - .help("Threshold to notify for a poor average cluster skip rate.") - ) - .arg( - Arg::with_name("max_poor_block_producer_percentage") - .long("max-poor-block-producer-percentage") - .value_name("PERCENTAGE") - .takes_value(true) - .default_value("20") - .validator(is_valid_percentage) - .help("Do not add or remove bonus stake from any non-delinquent validators if at least this percentage of all validators are poor block producers") - ) - .arg( - Arg::with_name("baseline_stake_amount") - .long("baseline-stake-amount") - .value_name("SOL") - .takes_value(true) - .default_value("5000") - .validator(is_amount) - ) - .arg( - Arg::with_name("bonus_stake_amount") - .long("bonus-stake-amount") - .value_name("SOL") - .takes_value(true) - .default_value("50000") - .validator(is_amount) - ) - .arg( - Arg::with_name("max_commission") - .long("max-commission") - .value_name("PERCENTAGE") - .takes_value(true) - .default_value("100") - .validator(is_valid_percentage) - .help("Vote accounts with a larger commission than this amount will not be staked") - ) - .arg( - Arg::with_name("min_release_version") - .long("min-release-version") - .value_name("SEMVER") - .takes_value(true) - .validator(is_release_version) - .help("Remove the base and bonus stake from validators with \ - a release version older than this one") - ) - .arg( - Arg::with_name("max_old_release_version_percentage") - .long("max-old-release-version-percentage") - .value_name("PERCENTAGE") - .takes_value(true) - .default_value("10") - .validator(is_valid_percentage) - .help("Do not remove stake from validators running older \ - software versions if more than this percentage of \ - all validators are running an older software version") - ) - .arg( - Arg::with_name("confirmed_block_cache_path") - .long("confirmed-block-cache-path") - .takes_value(true) - .value_name("PATH") - .default_value(&default_confirmed_block_cache_path) - .help("Base path of confirmed block cache") - ) - .arg( - Arg::with_name("max_infrastructure_concentration") - .long("max-infrastructure-concentration") - .takes_value(true) - .value_name("PERCENTAGE") - .default_value("100") - .validator(is_valid_percentage) - .help("Vote accounts sharing infrastructure with larger than this amount will not be staked") - ) - .arg( - Arg::with_name("infrastructure_concentration_affects") - .long("infrastructure-concentration-affects") - .takes_value(true) - .value_name("AFFECTS") - .default_value("warn") - .validator(|ref s| { - InfrastructureConcentrationAffects::from_str(s) - .map(|_| ()) - .map_err(|e| format!("{}", e)) - }) - .help("How validators with infrastruction concentration above \ - `max_infrastructure_concentration` will be affected. \ - Accepted values are: \ - 1) warn - Stake unaffected. A warning message \ - is notified \ - 2) destake - Removes all validator stake \ - 3) PATH_TO_YAML - Reads a list of validator identity \ - pubkeys from the specified YAML file \ - destaking those in the list and warning \ - any others") - ) - .arg( - Arg::with_name("use_cluster_average_skip_rate") - .long("use-cluster-average-skip-rate") - .help("Use a cluster-average skip rate floor for block-production quality calculations") - ) - .get_matches(); - - let config = if let Some(config_file) = matches.value_of("config_file") { - solana_cli_config::Config::load(config_file).unwrap_or_default() - } else { - solana_cli_config::Config::default() - }; - - let source_stake_address = pubkey_of(&matches, "source_stake_address").unwrap(); - let authorized_staker = keypair_of(&matches, "authorized_staker").unwrap(); - let dry_run = !matches.is_present("confirm"); - let cluster = value_t!(matches, "cluster", String).unwrap_or_else(|_| "unknown".into()); - let quality_block_producer_percentage = - value_t_or_exit!(matches, "quality_block_producer_percentage", usize); - let max_commission = value_t_or_exit!(matches, "max_commission", u8); - let max_poor_block_producer_percentage = - value_t_or_exit!(matches, "max_poor_block_producer_percentage", usize); - let max_old_release_version_percentage = - value_t_or_exit!(matches, "max_old_release_version_percentage", usize); - let baseline_stake_amount = - sol_to_lamports(value_t_or_exit!(matches, "baseline_stake_amount", f64)); - let bonus_stake_amount = sol_to_lamports(value_t_or_exit!(matches, "bonus_stake_amount", f64)); - let min_release_version = release_version_of(&matches, "min_release_version"); - - let (json_rpc_url, validator_list) = match cluster.as_str() { - "mainnet-beta" => ( - value_t!(matches, "json_rpc_url", String) - .unwrap_or_else(|_| "http://api.mainnet-beta.solana.com".into()), - validator_list::mainnet_beta_validators(), - ), - "testnet" => ( - value_t!(matches, "json_rpc_url", String) - .unwrap_or_else(|_| "http://testnet.solana.com".into()), - validator_list::testnet_validators(), - ), - "unknown" => { - let validator_list_file = - File::open(value_t_or_exit!(matches, "validator_list_file", PathBuf)) - .unwrap_or_else(|err| { - error!("Unable to open validator_list: {}", err); - process::exit(1); - }); - - let validator_list = serde_yaml::from_reader::<_, Vec>(validator_list_file) - .unwrap_or_else(|err| { - error!("Unable to read validator_list: {}", err); - process::exit(1); - }) - .into_iter() - .map(|p| { - Pubkey::from_str(&p).unwrap_or_else(|err| { - error!("Invalid validator_list pubkey '{}': {}", p, err); - process::exit(1); - }) - }) - .collect(); - ( - value_t!(matches, "json_rpc_url", String) - .unwrap_or_else(|_| config.json_rpc_url.clone()), - validator_list, - ) - } - _ => unreachable!(), - }; - let validator_list = validator_list.into_iter().collect::>(); - let confirmed_block_cache_path = matches - .value_of("confirmed_block_cache_path") - .map(PathBuf::from) - .unwrap(); - - let bad_cluster_average_skip_rate = - value_t!(matches, "bad_cluster_average_skip_rate", usize).unwrap_or(50); - let max_infrastructure_concentration = - value_t!(matches, "max_infrastructure_concentration", f64).unwrap(); - let infrastructure_concentration_affects = value_t!( - matches, - "infrastructure_concentration_affects", - InfrastructureConcentrationAffects - ) - .unwrap(); - let use_cluster_average_skip_rate = matches.is_present("use_cluster_average_skip_rate"); - - let config = Config { - json_rpc_url, - cluster, - source_stake_address, - authorized_staker, - validator_list, - dry_run, - baseline_stake_amount, - bonus_stake_amount, - delinquent_grace_slot_distance: 21600, // ~24 hours worth of slots at 2.5 slots per second - quality_block_producer_percentage, - max_commission, - max_poor_block_producer_percentage, - address_labels: config.address_labels, - min_release_version, - max_old_release_version_percentage, - confirmed_block_cache_path, - max_infrastructure_concentration, - infrastructure_concentration_affects, - use_cluster_average_skip_rate, - bad_cluster_average_skip_rate, - }; - - info!("RPC URL: {}", config.json_rpc_url); - config -} - -fn get_stake_account( - rpc_client: &RpcClient, - address: &Pubkey, -) -> Result<(u64, StakeState), String> { - let account = rpc_client.get_account(address).map_err(|e| { - format!( - "Failed to fetch stake account {}: {}", - address, - e.to_string() - ) - })?; - - if account.owner != solana_stake_program::id() { - return Err(format!( - "not a stake account (owned by {}): {}", - account.owner, address - )); - } - - account - .state() - .map_err(|e| { - format!( - "Failed to decode stake account at {}: {}", - address, - e.to_string() - ) - }) - .map(|stake_state| (account.lamports, stake_state)) -} - -pub fn retry_rpc_operation(mut retries: usize, op: F) -> client_error::Result -where - F: Fn() -> client_error::Result, -{ - loop { - let result = op(); - - if let Err(client_error::ClientError { - kind: client_error::ClientErrorKind::Reqwest(ref reqwest_error), - .. - }) = result - { - let can_retry = reqwest_error.is_timeout() - || reqwest_error - .status() - .map(|s| s == StatusCode::BAD_GATEWAY || s == StatusCode::GATEWAY_TIMEOUT) - .unwrap_or(false); - if can_retry && retries > 0 { - info!("RPC request timeout, {} retries remaining", retries); - retries -= 1; - continue; - } - } - return result; - } -} - -type BoxResult = Result>; - -/// quality poor cluster_skip_rate, too_many_poor_block_producers -type ClassifyResult = (HashSet, HashSet, usize, bool); - -fn classify_producers( - first_slot: Slot, - first_slot_in_epoch: Slot, - confirmed_blocks: HashSet, - leader_schedule: HashMap>, - config: &Config, -) -> BoxResult { - let mut poor_block_producers = HashSet::new(); - let mut quality_block_producers = HashSet::new(); - let mut blocks_and_slots = HashMap::new(); - - let mut total_blocks = 0; - let mut total_slots = 0; - for (validator_identity, relative_slots) in leader_schedule { - let mut validator_blocks = 0; - let mut validator_slots = 0; - for relative_slot in relative_slots { - let slot = first_slot_in_epoch + relative_slot as Slot; - if slot >= first_slot { - total_slots += 1; - validator_slots += 1; - if confirmed_blocks.contains(&slot) { - total_blocks += 1; - validator_blocks += 1; - } - } - } - if validator_slots > 0 { - let validator_identity = Pubkey::from_str(&validator_identity)?; - let e = blocks_and_slots.entry(validator_identity).or_insert((0, 0)); - e.0 += validator_blocks; - e.1 += validator_slots; - } - } - let cluster_average_rate = 100 - total_blocks * 100 / total_slots; - for (validator_identity, (blocks, slots)) in blocks_and_slots { - let skip_rate: usize = 100 - (blocks * 100 / slots); - let skip_rate_floor = if config.use_cluster_average_skip_rate { - cluster_average_rate - } else { - 0 - }; - if skip_rate.saturating_sub(config.quality_block_producer_percentage) >= skip_rate_floor { - poor_block_producers.insert(validator_identity); - } else { - quality_block_producers.insert(validator_identity); - } - trace!( - "Validator {} produced {} blocks in {} slots skip_rate: {}", - validator_identity, - blocks, - slots, - skip_rate, - ); - } - - let poor_block_producer_percentage = poor_block_producers.len() * 100 - / (quality_block_producers.len() + poor_block_producers.len()); - let too_many_poor_block_producers = - poor_block_producer_percentage > config.max_poor_block_producer_percentage; - - info!("cluster_average_skip_rate: {}", cluster_average_rate); - info!("quality_block_producers: {}", quality_block_producers.len()); - trace!("quality_block_producers: {:?}", quality_block_producers); - info!("poor_block_producers: {}", poor_block_producers.len()); - trace!("poor_block_producers: {:?}", poor_block_producers); - info!( - "poor_block_producer_percentage: {}% (too many poor producers={})", - poor_block_producer_percentage, too_many_poor_block_producers, - ); - - Ok(( - quality_block_producers, - poor_block_producers, - cluster_average_rate, - too_many_poor_block_producers, - )) -} - -/// Split validators into quality/poor lists based on their block production over the given `epoch` -fn classify_block_producers( - rpc_client: &RpcClient, - config: &Config, - epoch: Epoch, -) -> BoxResult { - let epoch_schedule = rpc_client.get_epoch_schedule()?; - let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch); - let last_slot_in_epoch = epoch_schedule.get_last_slot_in_epoch(epoch); - - let first_available_block = rpc_client.get_first_available_block()?; - let minimum_ledger_slot = rpc_client.minimum_ledger_slot()?; - debug!( - "first_available_block: {}, minimum_ledger_slot: {}", - first_available_block, minimum_ledger_slot - ); - - if first_available_block >= last_slot_in_epoch { - return Err(format!( - "First available block is newer than the last epoch: {} > {}", - first_available_block, last_slot_in_epoch - ) - .into()); - } - - let first_slot = if first_available_block > first_slot_in_epoch { - first_available_block - } else { - first_slot_in_epoch - }; - - let leader_schedule = rpc_client.get_leader_schedule(Some(first_slot))?.unwrap(); - - let cache_path = config.confirmed_block_cache_path.join(&config.cluster); - let cbc = ConfirmedBlockCache::open(cache_path, &config.json_rpc_url).unwrap(); - let confirmed_blocks = cbc - .query(first_slot, last_slot_in_epoch)? - .into_iter() - .collect::>(); - - classify_producers( - first_slot, - first_slot_in_epoch, - confirmed_blocks, - leader_schedule, - config, - ) -} - -fn validate_source_stake_account( - rpc_client: &RpcClient, - config: &Config, -) -> Result> { - // check source stake account - let (source_stake_balance, source_stake_state) = - get_stake_account(&rpc_client, &config.source_stake_address)?; - - info!( - "stake account balance: {} SOL", - lamports_to_sol(source_stake_balance) - ); - match &source_stake_state { - StakeState::Initialized(_) | StakeState::Stake(_, _) => source_stake_state - .authorized() - .map_or(Ok(source_stake_balance), |authorized| { - if authorized.staker != config.authorized_staker.pubkey() { - Err(format!( - "The authorized staker for the source stake account is not {}", - config.authorized_staker.pubkey() - ) - .into()) - } else { - Ok(source_stake_balance) - } - }), - _ => Err(format!( - "Source stake account is not in the initialized state: {:?}", - source_stake_state - ) - .into()), - } -} - -struct ConfirmedTransaction { - success: bool, - signature: Signature, - memo: String, -} - -/// Simulate a list of transactions and filter out the ones that will fail -fn simulate_transactions( - rpc_client: &RpcClient, - candidate_transactions: Vec<(Transaction, String)>, -) -> client_error::Result> { - info!("Simulating {} transactions", candidate_transactions.len(),); - let mut simulated_transactions = vec![]; - for (mut transaction, memo) in candidate_transactions { - transaction.message.recent_blockhash = - retry_rpc_operation(10, || rpc_client.get_recent_blockhash())?.0; - - let sim_result = rpc_client.simulate_transaction_with_config( - &transaction, - RpcSimulateTransactionConfig { - sig_verify: false, - ..RpcSimulateTransactionConfig::default() - }, - )?; - if sim_result.value.err.is_some() { - trace!( - "filtering out transaction due to simulation failure: {:?}: {}", - sim_result, - memo - ); - } else { - simulated_transactions.push((transaction, memo)) - } - } - info!( - "Successfully simulating {} transactions", - simulated_transactions.len() - ); - Ok(simulated_transactions) -} - -fn transact( - rpc_client: &RpcClient, - dry_run: bool, - transactions: Vec<(Transaction, String)>, - authorized_staker: &Keypair, -) -> Result, Box> { - let authorized_staker_balance = rpc_client.get_balance(&authorized_staker.pubkey())?; - info!( - "Authorized staker balance: {} SOL", - lamports_to_sol(authorized_staker_balance) - ); - - let (blockhash, fee_calculator, last_valid_slot) = rpc_client - .get_recent_blockhash_with_commitment(rpc_client.commitment())? - .value; - info!("{} transactions to send", transactions.len()); - - let required_fee = transactions.iter().fold(0, |fee, (transaction, _)| { - fee + fee_calculator.calculate_fee(&transaction.message) - }); - info!("Required fee: {} SOL", lamports_to_sol(required_fee)); - if required_fee > authorized_staker_balance { - return Err("Authorized staker has insufficient funds".into()); - } - - let mut pending_transactions = HashMap::new(); - for (mut transaction, memo) in transactions.into_iter() { - transaction.sign(&[authorized_staker], blockhash); - - pending_transactions.insert(transaction.signatures[0], memo); - if !dry_run { - rpc_client.send_transaction(&transaction)?; - } - } - - let mut finalized_transactions = vec![]; - loop { - if pending_transactions.is_empty() { - break; - } - - let slot = rpc_client.get_slot_with_commitment(CommitmentConfig::finalized())?; - info!( - "Current slot={}, last_valid_slot={} (slots remaining: {}) ", - slot, - last_valid_slot, - last_valid_slot.saturating_sub(slot) - ); - - if slot > last_valid_slot { - error!( - "Blockhash {} expired with {} pending transactions", - blockhash, - pending_transactions.len() - ); - - for (signature, memo) in pending_transactions.into_iter() { - finalized_transactions.push(ConfirmedTransaction { - success: false, - signature, - memo, - }); - } - break; - } - - let pending_signatures = pending_transactions.keys().cloned().collect::>(); - let mut statuses = vec![]; - for pending_signatures_chunk in - pending_signatures.chunks(MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS - 1) - { - trace!( - "checking {} pending_signatures", - pending_signatures_chunk.len() - ); - statuses.extend( - rpc_client - .get_signature_statuses(&pending_signatures_chunk)? - .value - .into_iter(), - ) - } - assert_eq!(statuses.len(), pending_signatures.len()); - - for (signature, status) in pending_signatures.into_iter().zip(statuses.into_iter()) { - info!("{}: status={:?}", signature, status); - let completed = if dry_run { - Some(true) - } else if let Some(status) = &status { - if status.confirmations.is_none() || status.err.is_some() { - Some(status.err.is_none()) - } else { - None - } - } else { - None - }; - - if let Some(success) = completed { - warn!("{}: completed. success={}", signature, success); - let memo = pending_transactions.remove(&signature).unwrap(); - finalized_transactions.push(ConfirmedTransaction { - success, - signature, - memo, - }); - } - } - sleep(Duration::from_secs(5)); - } - - Ok(finalized_transactions) -} - -fn process_confirmations( - mut confirmations: Vec, - notifier: Option<&Notifier>, -) -> bool { - let mut ok = true; - - confirmations.sort_by(|a, b| a.memo.cmp(&b.memo)); - for ConfirmedTransaction { - success, - signature, - memo, - } in confirmations - { - if success { - info!("OK: {}: {}", signature, memo); - if let Some(notifier) = notifier { - notifier.send(&memo) - } - } else { - error!("FAIL: {}: {}", signature, memo); - ok = false - } - } - ok -} - -const DATA_CENTER_ID_UNKNOWN: &str = "0-Unknown"; - -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -struct DataCenterId { - asn: u64, - location: String, -} - -impl Default for DataCenterId { - fn default() -> Self { - Self::from_str(DATA_CENTER_ID_UNKNOWN).unwrap() - } -} - -impl std::str::FromStr for DataCenterId { - type Err = String; - fn from_str(s: &str) -> Result { - let mut parts = s.splitn(2, '-'); - let asn = parts.next(); - let location = parts.next(); - if let (Some(asn), Some(location)) = (asn, location) { - let asn = asn.parse().map_err(|e| format!("{:?}", e))?; - let location = location.to_string(); - Ok(Self { asn, location }) - } else { - Err(format!("cannot construct DataCenterId from input: {}", s)) - } - } -} - -impl std::fmt::Display for DataCenterId { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}-{}", self.asn, self.location) - } -} - -#[derive(Clone, Debug, Default)] -struct DatacenterInfo { - id: DataCenterId, - stake: u64, - stake_percent: f64, - validators: Vec, -} - -impl DatacenterInfo { - pub fn new(id: DataCenterId) -> Self { - Self { - id, - ..Self::default() - } - } -} - -impl std::fmt::Display for DatacenterInfo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "{:<30} {:>20} {:>5.2} {}", - self.id.to_string(), - self.stake, - self.stake_percent, - self.validators.len() - ) - } -} - -fn get_data_center_info() -> Result, Box> { - let token = std::env::var("VALIDATORS_APP_TOKEN")?; - let client = validators_app::Client::new(token); - let validators = client.validators(None, None)?; - let mut data_center_infos = HashMap::new(); - let mut total_stake = 0; - let mut unknown_data_center_stake: u64 = 0; - for v in validators.as_ref() { - let account = v - .account - .as_ref() - .and_then(|pubkey| Pubkey::from_str(pubkey).ok()); - let account = if let Some(account) = account { - account - } else { - warn!("No vote pubkey for: {:?}", v); - continue; - }; - - let stake = v.active_stake.unwrap_or(0); - - let data_center = v - .data_center_key - .as_deref() - .or_else(|| { - unknown_data_center_stake = unknown_data_center_stake.saturating_add(stake); - None - }) - .unwrap_or(DATA_CENTER_ID_UNKNOWN); - let data_center_id = DataCenterId::from_str(data_center) - .map_err(|e| { - unknown_data_center_stake = unknown_data_center_stake.saturating_add(stake); - e - }) - .unwrap_or_default(); - - let mut data_center_info = data_center_infos - .entry(data_center_id.clone()) - .or_insert_with(|| DatacenterInfo::new(data_center_id)); - data_center_info.stake += stake; - total_stake += stake; - data_center_info.validators.push(account); - } - - let unknown_percent = 100f64 * (unknown_data_center_stake as f64) / total_stake as f64; - if unknown_percent > 3f64 { - warn!("unknown data center percentage: {:.0}%", unknown_percent); - } - - let data_center_infos = data_center_infos - .drain() - .map(|(_, mut i)| { - i.stake_percent = 100f64 * i.stake as f64 / total_stake as f64; - i - }) - .collect(); - Ok(data_center_infos) -} - -#[allow(clippy::cognitive_complexity)] // Yeah I know... -fn main() -> Result<(), Box> { - solana_logger::setup_with_default("solana=info"); - let config = get_config(); - - let notifier = Notifier::default(); - let rpc_client = RpcClient::new(config.json_rpc_url.clone()); - - if !config.dry_run && notifier.is_empty() { - error!("A notifier must be active with --confirm"); - process::exit(1); - } - - // Sanity check that the RPC endpoint is healthy before performing too much work - rpc_client.get_health().unwrap_or_else(|err| { - error!("RPC endpoint is unhealthy: {:?}", err); - process::exit(1); - }); - - let cluster_nodes_with_old_version: HashSet = match config.min_release_version { - Some(ref min_release_version) => rpc_client - .get_cluster_nodes()? - .into_iter() - .filter_map(|rpc_contact_info| { - if let Ok(pubkey) = Pubkey::from_str(&rpc_contact_info.pubkey) { - if config.validator_list.contains(&pubkey) { - if let Some(ref version) = rpc_contact_info.version { - if let Ok(semver) = semver::Version::parse(version) { - if semver < *min_release_version { - return Some(rpc_contact_info.pubkey); - } - } - } - } - } - None - }) - .collect(), - None => HashSet::default(), - }; - - if let Some(ref min_release_version) = config.min_release_version { - info!( - "Validators running a release older than {}: {:?}", - min_release_version, cluster_nodes_with_old_version, - ); - } - - let source_stake_balance = validate_source_stake_account(&rpc_client, &config)?; - - let epoch_info = rpc_client.get_epoch_info()?; - let last_epoch = epoch_info.epoch - 1; - - info!("Epoch info: {:?}", epoch_info); - - let ( - quality_block_producers, - poor_block_producers, - cluster_average_skip_rate, - too_many_poor_block_producers, - ) = classify_block_producers(&rpc_client, &config, last_epoch)?; - - let too_many_old_validators = cluster_nodes_with_old_version.len() - > (poor_block_producers.len() + quality_block_producers.len()) - * config.max_old_release_version_percentage - / 100; - - // Fetch vote account status for all the validator_listed validators - let vote_account_status = rpc_client.get_vote_accounts()?; - let vote_account_info = vote_account_status - .current - .into_iter() - .chain(vote_account_status.delinquent.into_iter()) - .filter_map(|vai| { - let node_pubkey = Pubkey::from_str(&vai.node_pubkey).ok()?; - if config.validator_list.contains(&node_pubkey) { - Some(vai) - } else { - None - } - }) - .collect::>(); - - let infrastructure_concentration = get_data_center_info() - .map_err(|e| { - warn!("infrastructure concentration skipped: {}", e); - e - }) - .unwrap_or_default() - .drain(..) - .filter_map(|dci| { - if dci.stake_percent > config.max_infrastructure_concentration { - Some((dci.validators, dci.stake_percent)) - } else { - None - } - }) - .flat_map(|(v, sp)| v.into_iter().map(move |v| (v, sp))) - .collect::>(); - - let mut source_stake_lamports_required = 0; - let mut create_stake_transactions = vec![]; - let mut delegate_stake_transactions = vec![]; - let mut stake_activated_in_current_epoch: HashSet = HashSet::new(); - let mut infrastructure_concentration_warnings = vec![]; - - for RpcVoteAccountInfo { - commission, - node_pubkey: node_pubkey_str, - root_slot, - vote_pubkey, - .. - } in &vote_account_info - { - let formatted_node_pubkey = - format_labeled_address(&node_pubkey_str, &config.address_labels); - let node_pubkey = Pubkey::from_str(&node_pubkey_str).unwrap(); - let baseline_seed = &vote_pubkey.to_string()[..32]; - let bonus_seed = &format!("A{{{}", vote_pubkey)[..32]; - let vote_pubkey = Pubkey::from_str(&vote_pubkey).unwrap(); - - let baseline_stake_address = Pubkey::create_with_seed( - &config.authorized_staker.pubkey(), - baseline_seed, - &solana_stake_program::id(), - ) - .unwrap(); - let bonus_stake_address = Pubkey::create_with_seed( - &config.authorized_staker.pubkey(), - bonus_seed, - &solana_stake_program::id(), - ) - .unwrap(); - - debug!( - "\nidentity: {}\n - vote address: {}\n - root slot: {}\n - baseline stake: {}\n - bonus stake: {}", - node_pubkey, vote_pubkey, root_slot, baseline_stake_address, bonus_stake_address - ); - - // Transactions to create the baseline and bonus stake accounts - if let Ok((balance, stake_state)) = get_stake_account(&rpc_client, &baseline_stake_address) - { - if balance <= config.baseline_stake_amount { - info!( - "Unexpected balance in stake account {}: {}, expected {}", - baseline_stake_address, balance, config.baseline_stake_amount - ); - } - if let Some(delegation) = stake_state.delegation() { - if epoch_info.epoch == delegation.activation_epoch { - stake_activated_in_current_epoch.insert(baseline_stake_address); - } - } - } else { - info!( - "Need to create baseline stake account for validator {}", - formatted_node_pubkey - ); - source_stake_lamports_required += config.baseline_stake_amount; - create_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &stake_instruction::split_with_seed( - &config.source_stake_address, - &config.authorized_staker.pubkey(), - config.baseline_stake_amount, - &baseline_stake_address, - &config.authorized_staker.pubkey(), - baseline_seed, - ), - Some(&config.authorized_staker.pubkey()), - )), - format!( - "Creating baseline stake account for validator {} ({})", - formatted_node_pubkey, baseline_stake_address - ), - )); - } - - if let Ok((balance, stake_state)) = get_stake_account(&rpc_client, &bonus_stake_address) { - if balance <= config.bonus_stake_amount { - info!( - "Unexpected balance in stake account {}: {}, expected {}", - bonus_stake_address, balance, config.bonus_stake_amount - ); - } - if let Some(delegation) = stake_state.delegation() { - if epoch_info.epoch == delegation.activation_epoch { - stake_activated_in_current_epoch.insert(bonus_stake_address); - } - } - } else { - info!( - "Need to create bonus stake account for validator {}", - formatted_node_pubkey - ); - source_stake_lamports_required += config.bonus_stake_amount; - create_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &stake_instruction::split_with_seed( - &config.source_stake_address, - &config.authorized_staker.pubkey(), - config.bonus_stake_amount, - &bonus_stake_address, - &config.authorized_staker.pubkey(), - bonus_seed, - ), - Some(&config.authorized_staker.pubkey()), - )), - format!( - "Creating bonus stake account for validator {} ({})", - formatted_node_pubkey, bonus_stake_address - ), - )); - } - - let infrastructure_concentration_destake_memo = infrastructure_concentration - .get(&node_pubkey) - .map(|concentration| { - config.infrastructure_concentration_affects.memo( - &node_pubkey, - *concentration, - &config, - ) - }) - .and_then(|affect| match affect { - InfrastructureConcentrationAffectKind::Destake(memo) => Some(memo), - InfrastructureConcentrationAffectKind::Warn(memo) => { - infrastructure_concentration_warnings.push(memo); - None - } - }); - - if let Some(memo_base) = infrastructure_concentration_destake_memo { - // Deactivate baseline stake - delegate_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &[stake_instruction::deactivate_stake( - &baseline_stake_address, - &config.authorized_staker.pubkey(), - )], - Some(&config.authorized_staker.pubkey()), - )), - format!("{} {}", memo_base, "base stake"), - )); - - // Deactivate bonus stake - delegate_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &[stake_instruction::deactivate_stake( - &bonus_stake_address, - &config.authorized_staker.pubkey(), - )], - Some(&config.authorized_staker.pubkey()), - )), - format!("{} {}", memo_base, "bonus stake"), - )); - } else if *commission > config.max_commission { - // Deactivate baseline stake - delegate_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &[stake_instruction::deactivate_stake( - &baseline_stake_address, - &config.authorized_staker.pubkey(), - )], - Some(&config.authorized_staker.pubkey()), - )), - format!( - "⛔ `{}` commission of {}% is too high. Max commission is {}%. Removed ◎{} baseline stake", - formatted_node_pubkey, - commission, - config.max_commission, - lamports_to_sol(config.baseline_stake_amount), - ), - )); - - // Deactivate bonus stake - delegate_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &[stake_instruction::deactivate_stake( - &bonus_stake_address, - &config.authorized_staker.pubkey(), - )], - Some(&config.authorized_staker.pubkey()), - )), - format!( - "⛔ `{}` commission of {}% is too high. Max commission is {}%. Removed ◎{} bonus stake", - formatted_node_pubkey, - commission, - config.max_commission, - lamports_to_sol(config.bonus_stake_amount), - ), - )); - } else if !too_many_old_validators - && cluster_nodes_with_old_version.contains(node_pubkey_str) - { - // Deactivate baseline stake - delegate_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &[stake_instruction::deactivate_stake( - &baseline_stake_address, - &config.authorized_staker.pubkey(), - )], - Some(&config.authorized_staker.pubkey()), - )), - format!( - "🧮 `{}` is running an old software release. Removed ◎{} baseline stake", - formatted_node_pubkey, - lamports_to_sol(config.baseline_stake_amount), - ), - )); - - // Deactivate bonus stake - delegate_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &[stake_instruction::deactivate_stake( - &bonus_stake_address, - &config.authorized_staker.pubkey(), - )], - Some(&config.authorized_staker.pubkey()), - )), - format!( - "🧮 `{}` is running an old software release. Removed ◎{} bonus stake", - formatted_node_pubkey, - lamports_to_sol(config.bonus_stake_amount), - ), - )); - - // Validator is not considered delinquent if its root slot is less than 256 slots behind the current - // slot. This is very generous. - } else if *root_slot > epoch_info.absolute_slot - 256 { - datapoint_info!( - "validator-status", - ("cluster", config.cluster, String), - ("id", node_pubkey.to_string(), String), - ("slot", epoch_info.absolute_slot, i64), - ("root-slot", *root_slot, i64), - ("ok", true, bool) - ); - - // Delegate baseline stake - if !stake_activated_in_current_epoch.contains(&baseline_stake_address) { - delegate_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &[stake_instruction::delegate_stake( - &baseline_stake_address, - &config.authorized_staker.pubkey(), - &vote_pubkey, - )], - Some(&config.authorized_staker.pubkey()), - )), - format!( - "🥩 `{}` is current. Added ◎{} baseline stake", - formatted_node_pubkey, - lamports_to_sol(config.baseline_stake_amount), - ), - )); - } - - if !too_many_poor_block_producers { - if quality_block_producers.contains(&node_pubkey) { - // Delegate bonus stake - if !stake_activated_in_current_epoch.contains(&bonus_stake_address) { - delegate_stake_transactions.push(( - Transaction::new_unsigned( - Message::new( - &[stake_instruction::delegate_stake( - &bonus_stake_address, - &config.authorized_staker.pubkey(), - &vote_pubkey, - )], - Some(&config.authorized_staker.pubkey()), - )), - format!( - "🏅 `{}` was a quality block producer during epoch {}. Added ◎{} bonus stake", - formatted_node_pubkey, - last_epoch, - lamports_to_sol(config.bonus_stake_amount), - ), - )); - } - } else if poor_block_producers.contains(&node_pubkey) { - // Deactivate bonus stake - delegate_stake_transactions.push(( - Transaction::new_unsigned( - Message::new( - &[stake_instruction::deactivate_stake( - &bonus_stake_address, - &config.authorized_staker.pubkey(), - )], - Some(&config.authorized_staker.pubkey()), - )), - format!( - "💔 `{}` was a poor block producer during epoch {}. Removed ◎{} bonus stake", - formatted_node_pubkey, - last_epoch, - lamports_to_sol(config.bonus_stake_amount), - ), - )); - } - } - } else { - // Destake the validator if it has been delinquent for longer than the grace period - if *root_slot - < epoch_info - .absolute_slot - .saturating_sub(config.delinquent_grace_slot_distance) - { - // Deactivate baseline stake - delegate_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &[stake_instruction::deactivate_stake( - &baseline_stake_address, - &config.authorized_staker.pubkey(), - )], - Some(&config.authorized_staker.pubkey()), - )), - format!( - "🏖️ `{}` is delinquent. Removed ◎{} baseline stake", - formatted_node_pubkey, - lamports_to_sol(config.baseline_stake_amount), - ), - )); - - // Deactivate bonus stake - delegate_stake_transactions.push(( - Transaction::new_unsigned(Message::new( - &[stake_instruction::deactivate_stake( - &bonus_stake_address, - &config.authorized_staker.pubkey(), - )], - Some(&config.authorized_staker.pubkey()), - )), - format!( - "🏖️ `{}` is delinquent. Removed ◎{} bonus stake", - formatted_node_pubkey, - lamports_to_sol(config.bonus_stake_amount), - ), - )); - - datapoint_info!( - "validator-status", - ("cluster", config.cluster, String), - ("id", node_pubkey.to_string(), String), - ("slot", epoch_info.absolute_slot, i64), - ("root-slot", *root_slot, i64), - ("ok", false, bool) - ); - } else { - // The validator is still considered current for the purposes of metrics reporting, - datapoint_info!( - "validator-status", - ("cluster", config.cluster, String), - ("id", node_pubkey.to_string(), String), - ("slot", epoch_info.absolute_slot, i64), - ("root-slot", *root_slot, i64), - ("ok", true, bool) - ); - } - } - } - - if create_stake_transactions.is_empty() { - info!("All stake accounts exist"); - } else { - info!( - "{} SOL is required to create {} stake accounts", - lamports_to_sol(source_stake_lamports_required), - create_stake_transactions.len() - ); - if source_stake_balance < source_stake_lamports_required { - error!( - "Source stake account has insufficient balance: {} SOL, but {} SOL is required", - lamports_to_sol(source_stake_balance), - lamports_to_sol(source_stake_lamports_required) - ); - process::exit(1); - } - - let create_stake_transactions = - simulate_transactions(&rpc_client, create_stake_transactions)?; - let confirmations = transact( - &rpc_client, - config.dry_run, - create_stake_transactions, - &config.authorized_staker, - )?; - - if !process_confirmations(confirmations, None) { - error!("Failed to create one or more stake accounts. Unable to continue"); - process::exit(1); - } - } - - let delegate_stake_transactions = - simulate_transactions(&rpc_client, delegate_stake_transactions)?; - let confirmations = transact( - &rpc_client, - config.dry_run, - delegate_stake_transactions, - &config.authorized_staker, - )?; - - if cluster_average_skip_rate > config.bad_cluster_average_skip_rate { - let message = format!( - "Cluster average skip rate: {} is above threshold: {}", - cluster_average_skip_rate, config.bad_cluster_average_skip_rate - ); - warn!("{}", message); - if !config.dry_run { - notifier.send(&message); - } - } - - if too_many_poor_block_producers { - let message = format!( - "Note: Something is wrong, more than {}% of validators classified \ - as poor block producers in epoch {}. Bonus stake frozen", - config.max_poor_block_producer_percentage, last_epoch, - ); - warn!("{}", message); - if !config.dry_run { - notifier.send(&message); - } - } - - if too_many_old_validators { - let message = format!( - "Note: Something is wrong, more than {}% of validators classified \ - as running an older release", - config.max_old_release_version_percentage - ); - warn!("{}", message); - if !config.dry_run { - notifier.send(&message); - } - } - - let confirmations_succeeded = process_confirmations( - confirmations, - if config.dry_run { - None - } else { - Some(¬ifier) - }, - ); - - for memo in &infrastructure_concentration_warnings { - if config.dry_run && !notifier.is_empty() { - notifier.send(memo) - } - } - - if !confirmations_succeeded { - process::exit(1); - } - - Ok(()) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_quality_producer_with_average_skip_rate() { - solana_logger::setup(); - let config = Config { - quality_block_producer_percentage: 10, - max_poor_block_producer_percentage: 40, - use_cluster_average_skip_rate: true, - ..Config::default_for_test() - }; - - let confirmed_blocks: HashSet = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 21, 22, 43, 44, 45, 46, 47, 48, - ] - .iter() - .cloned() - .collect(); - let mut leader_schedule = HashMap::new(); - let l1 = Pubkey::new_unique(); - let l2 = Pubkey::new_unique(); - let l3 = Pubkey::new_unique(); - let l4 = Pubkey::new_unique(); - let l5 = Pubkey::new_unique(); - leader_schedule.insert(l1.to_string(), (0..10).collect()); - leader_schedule.insert(l2.to_string(), (10..20).collect()); - leader_schedule.insert(l3.to_string(), (20..30).collect()); - leader_schedule.insert(l4.to_string(), (30..40).collect()); - leader_schedule.insert(l5.to_string(), (40..50).collect()); - let (quality, poor, _cluster_average, too_many_poor_block_producers) = - classify_producers(0, 0, confirmed_blocks, leader_schedule, &config).unwrap(); - assert!(quality.contains(&l1)); - assert!(quality.contains(&l5)); - assert!(quality.contains(&l2)); - assert!(poor.contains(&l3)); - assert!(poor.contains(&l4)); - assert!(!too_many_poor_block_producers); - } - - #[test] - fn test_quality_producer_when_all_poor() { - solana_logger::setup(); - let config = Config { - quality_block_producer_percentage: 10, - use_cluster_average_skip_rate: false, - ..Config::default_for_test() - }; - - let confirmed_blocks = HashSet::::new(); - let mut leader_schedule = HashMap::new(); - let l1 = Pubkey::new_unique(); - let l2 = Pubkey::new_unique(); - let l3 = Pubkey::new_unique(); - let l4 = Pubkey::new_unique(); - let l5 = Pubkey::new_unique(); - leader_schedule.insert(l1.to_string(), (0..10).collect()); - leader_schedule.insert(l2.to_string(), (10..20).collect()); - leader_schedule.insert(l3.to_string(), (20..30).collect()); - leader_schedule.insert(l4.to_string(), (30..40).collect()); - leader_schedule.insert(l5.to_string(), (40..50).collect()); - let (quality, poor, _cluster_average, too_many_poor_block_producers) = - classify_producers(0, 0, confirmed_blocks, leader_schedule, &config).unwrap(); - assert!(quality.is_empty()); - assert_eq!(poor.len(), 5); - assert!(too_many_poor_block_producers); - } -} diff --git a/stake-o-matic/src/validator_list.rs b/stake-o-matic/src/validator_list.rs deleted file mode 100644 index 18edcbd5bb..0000000000 --- a/stake-o-matic/src/validator_list.rs +++ /dev/null @@ -1,1865 +0,0 @@ -solana_sdk::pubkeys!( - testnet_validators, - [ - "123vij84ecQEKUvQ7gYMKxKwKF6PbYSzCzzURYA4xULY", - "12NG4Y7LGq8VQgtDZxn82ok4eGUEqmhzKh3wZtsakjLN", - "12Y25eHzGPaK5R5DjQ1kgJWuVd7zrtQ7cmaMPfmacsJV", - "13nbrL1VjkfTZuaz7rNriYw6fWDFggqEf2g1C4mPETkr", - "234u57PuEif5LkTBwS7rHzu1XF5VWg79ddLLDkYBh44Q", - "238Fmy2TwU26Fo8XFRu2PzDWNbcn3bitywEPYG6tpztu", - "23SUe5fzmLws1M58AnGnvnUBRUKJmzCpnFQwv4M4b9Er", - "23vHFSzVQAqbUQkTMaogVbPuyWM3RbKowC9jnEXQVFm6", - "25UM59KCvciYwhjCq7t1rC8ZuvsxQBC2QRcaRNfq7xML", - "27SB7d27xvtBJjgsAV8JBDjQroySmZepiNSepeRbRhe9", - "28LgQ7MeEZVgNJfYRc6UnoAz2SnSjKbyCKM6sntCRotb", - "295DP6WSsiJ3oLNPhZ3oSZUA6gwbGe7KDoHWRnRBZAHu", - "29tXWWzvGNvE5j8i6FLfHpmanPC9treZsCo1uA4ik1kL", - "29Xwdi4HpBr1u9EAqDz3tBbMuwqBuczLPuVe2gGkg7ZF", - "2bQyrSEPaQ9BMbu7Ftv7ye1fxtSLW3oZRj4d2U64AJmc", - "2BT25HZHpyzYmTbqyqzxBK7YjjH4a6aZ783TEgTTGYo5", - "2bvUqyatpaDLn9ch9BxNYRwg5SFpq3rDfWJKfohC9iD4", - "2C26iHJcU5dqJJQ6NME3Lq583RT1Js9QDtgfmzknRajc", - "2C9pDcbRQJxbUHivgDdg4LGuMwm5oeVCnHS9w5JktNTo", - "2Ceu5z672tACCDB6cmB3n4tih7B8dikv6k6kfYr3Li1e", - "2CGskjnksG9YwAFMJkPDwsKx1iRAXJSzfpAxyoWzGj6M", - "2CJnVLz7tMWQDHHRkyXQpnaFF95i5FZsGU9NZcUdWJ2h", - "2cxgydEWqiVTookrgPWucNuQqmwThyoNAYPX3GqeDdvh", - "2D1oCLRK6geGhV5RyZ52JD9Qzqt311AEH1XrTjZdzbRh", - "2dg2NiZC1LyC5LbUsv3sJYU1LhAqkJrK23J6hssoLJAA", - "2dm9YbgXtR5yimmgsLkfaMLcNZxhjywW4bLnvChms3tb", - "2DvsPbbKrBaJm7SbdVvRjZL1NGCU3MwciGCoCw42fTMu", - "2dYoJ9T45W6N8bCaccesfJ3i2diazR7YkyeLMX4okKth", - "2eDDjJSKdxf8qwojH1E2SoZFHqst56GXxtmAnoZtGdtu", - "2eoKP1tzZkkXWexUY7XHLSNbo9DbuFGBssfhp8zCcdwH", - "2EQekczAd7QmnWhmPpbhCCsWeFooqZmQqHNz8qo8S8RA", - "2FCxeG7mBYy2kpYgvgTZLCYXnaqDc4hGwYunhzHmEUD1", - "2GAdxV8QafdRnkTwy9AuX8HvVcNME6JqK2yANaDunhXp", - "2GAtWPFNhEfj6nmXJp2YqPhSY55TvLeZpLRq9t3hqi1F", - "2gV5onEfn8KmtZ3Lck39GrNEZyTxJ1RiNV5s7fRdC3gc", - "2gx4am78NPRPxEW1CKg6yZ3viFob4bHnz6AUDSCMnmp4", - "2iAP1WMsKJVje22cgPJNGC7Jgv5DQj37QZwcDNUDd9F3", - "2ibbdJtxwzzzhK3zc7FR3cfea2ATHwCJ8ybcG7WzKtBd", - "2iczkZceGZQqimksY8uk6NLrQXoMFZGK1mTWos4QnZ3a", - "2jrM8c8ZhpX9CovseJ2sRsrU9yzsFrP7d3gCi5ESU5Rs", - "2JT1SRSm61vvHKErY2PCnHUtMsumoh69jrC7bojd9f1x", - "2jypS1SoX6MLEfuNvUH23K7UU3BsRu3vBphcd7BVkEpj", - "2jYzt9Ly7dNzNpMV9sbHBNuwMEvVdSi9L8yJCTJT21ki", - "2K2UhSoUNNi7Q78F5QCpcutRaifTjckGYKLpsw7i9noa", - "2KCo4n2nFpAAVec2NS46XHWpWRKcDLu6sR9fPSbCb3nS", - "2khFqurxeMKKfhFJ9dfas1L9LsHwt2qHGW8Ztinzoeob", - "2LsRRgttA1PKXXeKTZP2QhetgM94Dj5uecmTzyQkTvXK", - "2mEvgikTj9SRL59MXogmYfyAR9ze51HV5dCgPUEj6V5t", - "2ofEZBxkiZoBpxXcXT68RTHfuQQFChSYVXVPGbFfvMTP", - "2p64GWwGEWtHdwjdeXCMHU5LBstm5BenLdGsJZzDrKHH", - "2Pik6jn6yLQVi8jmwvZCibTygPWvhh3pXoGJrGT3eVGf", - "2PSBMBFVykqSc4MFQ3krJVRosjmixSbNeNJfGMmL1DFp", - "2PvsR9DM2GZavFQGDsdJwXJvPWsyneyT9Gpu7wXGDkSr", - "2qRkFXBL3Ej7vzPCTnygaKVA8mNMPe66w762oHLYWrDH", - "2qYB7wEBJ1UstVNZLbWyvTXNfocSsWEh7cFaTLkqsvfR", - "2RLf3RSy1ScBFL5UzVDw3jYKCAuGA9vHpr9dnbQzJt8V", - "2ryEov5c84JLWwt5Ub1xGYWux1LF63j7kaNRc6jiv4As", - "2RYnM1C5XuzWzZu4sD7TyJTgxQTKzFVHG6jNtbK65q2y", - "2sBsdFT58SPfd5LQyE8MhEgJWpaoHUCoN4QFCVqNZpnj", - "2TcLzmdcpQqbNEBjU2Hxp1MiETSww1HJeWW84F61Z13k", - "2tvTYUajoBgeAd66Zhd5Nc2BgKGCgdmasR94fpBokzop", - "2tZoLFgcbeW8Howq8QMRnExvuwHFUeEnx9ZhHq2qX77E", - "2URaCX9G2dKKrtwygpZemfTpDivpSNT31T25vX4YGR4R", - "2uzuT8dgVVLLgG57n5W9vxMTaNAaLavnt8gtiF7V1FVV", - "2vobGAfskQtdSCFHhrmMCK9PFojyGPhSxYtjDP8irkqE", - "2VzCLy98rzmvKGo23e1eM4LANCt9JFrtVTBBMZzGT4FW", - "2X5JSTLN9m2wm3ejCxfWRNMieuC2VMtaMWSoqLPbC4Pq", - "2XAHomUvH3LFjYSxzSfcbwS73JgynpQHfapMNMJ8isL9", - "2xFjhfxTKGVvGDXLwroqGiKNEF3KCSFaCRVLHfpsiPgd", - "2xoWe7LGX8Kmnwoc27VF2iYkxfKESjb3b9rU1iM9wHJT", - "2XP9MfzWQnX3DiAJQFSKXKyqBr4M7GKhHnKc9P7z519H", - "2y857Ss2GgyL9WooNqt6sAgxDVwr9pE6i4BiJ2wrC4g3", - "2yDwZer11v2TTj86WeHzRDpE4HJVbyJ3fJ8H4AkUtWTc", - "2YgttBBx9Ax6WhF9xu8CSWw5usKFWxaxzJtg8zPajadx", - "2YhQPcbz1NYuu1B7Kpxi2NGrpZ8Jdv9azw8Jf6E9FC71", - "2YLPihCDxqztR5be69jhoNDPMxV6KeTJ2X2LtVBXDgp4", - "2YtaVYd8fZHXpPezG5gRp9nudXGBEPcqFtJe8ikN1DZ7", - "2ZeChc7Res7fUVdcGCDTJfRd9N8R21hiBPLAuJsqHHwh", - "2ZETk6Sy3wdrbTRRCFa6u1gzNjg59B5yFJwjiACC6Evc", - "2zF9q2xyKpsu9CSGJDj81j3N9ryvrhPRcjCkzafCezsg", - "2zHkPFBSxWF4Bc6P7XHaZMJLfBqtSgfDCBqTZ7STXE1a", - "2zQSe8o4xws8q3tMFU5AoPxMzu1JZoufR3tsZ1zknHiK", - "2ZuLSKq6t5nqRLp3GqtRSttu7FE9if2nrMegHLnp5skK", - "2ZZkgKcBfp4tW8qCLj2yjxRYh9CuvEVJWb6e2KKS91Mj", - "31cud34DHkL5zM4ZiHXgsrkAu13Jeck7ahvkPU9i4Jze", - "33FtaV5DrLUPYYQK7QAiD3LBDXD2VoCv6BuCQVoRdq57", - "33kmrfcRXVtWZxmVJ1GTsPNKpBXWTj1tv65wTVTiifyw", - "33LfdA2yKS6m7E8pSanrKTKYMhpYHEGaSWtNNB5s7xnm", - "34D4nS1eywoA1wiwcgrBP8Ewj9NXyaZ3dP9DJKfkvpGn", - "368KipD4nBzVs4AizHj1iU4TErSSqmZaNGVyzHx8TVXM", - "36gARMU4V3D6hu5EJi7wYFW6cC1tNym9DkjZfAGFQTbk", - "36GQk6L2UmRhy7T3Vjb75HySi7226SK4eHn9WpycmZst", - "37Gr1zVPr79E3AdPFj8EMyKZYt7Bnz3VWKjdFctQC8fL", - "383CX582368Zao48isK6qp33xBphCvhfgdEowfiXeG1k", - "38hgERMK335yrDsyPkc4wbW2FUiXgmuWRght9n7RVAtz", - "38zXVD94Hp71ftxT5JqeTYzTGECk1BmiSJVoXzbS7jsR", - "39FH4cnkSawRtr9N2VbUVST4o6ZiixW2K4QCzLqW8tMg", - "39moskfERPLyaspZAZNsbrXgiUxWGGgyjPWu1ZaN2dJv", - "3adqz1JN9sbsjHGxQizz2ibJmyCHtUpP9aPnZYxixB4c", - "3ANJb42D3pkVtntgT6VtW2cD3icGVyoHi2NGwtXYHQAs", - "3bcAoEkLDKNuFg77wzCx2dbPNSgeZVF5AYHDet1rPyd8", - "3BCokPfahX9rLYMh6E6uYTEFuchiKd9wZcXUvwDHFYiH", - "3bQ4s7ynWKjEPrkTfDx1aT2sXejXXYjbfYumBHc5LA83", - "3cJeH1TCZcNf5gCZnSbfZne9DQCiexkzuH6gwQEeBjqA", - "3ckQZncmgmS1aZCC7Eot659hoBQ8k85ExddD7fu9qJ2c", - "3Df9iVRoSkX3YZ6GmMexeLSX8vyt8BADpHn571KfQSWa", - "3dVEmuYaJxLdLNGnNxCuLtELp38VKMxJPY6gUJScu6Jc", - "3F6wMGB5C5fB7xtTMmJ8NAfkwmWSaQgxPsBUBgveZvrQ", - "3FhfNWGiqDsy4xAXiS74WUb5GLfK7FVnn6kxt3CYLgvr", - "3Fiu2KFBf3BoT9REvsFbpb7L1vTSs7jnmuDrk4vZ9DNE", - "3g7c1Mufk7Bi8Kk4wKTGQ3eLwfHYqc7ySpP46fqEMsEC", - "3gEaREHMBHTafrMHrFgibZeDq73GUeiiZt8U1KGwDVGE", - "3HitRjngqhAgVuNdFwtR1Lp5tQavbJri8MvKUq5Jpw1N", - "3ht1z7tMieDiLkukray7AauF214xtsWFFG1E4A1oeAXU", - "3i7sS5McrJ7EzU8nbdA5rcXT9kNiSxLxhwyfuxbsDvBj", - "3iPu9xQ3mCFmqME9ZajuZbFHjwagAxhgfTxnc4pWbEBC", - "3jddze9ZFYxTfVkV7xr78TSSkLahj6Zf1G3TUrhnWQuw", - "3JeLfM9V7CkK1D8W8LFirU65AZsWRo127PumwNc3dFQi", - "3JfoYf6wmQxhpry1L61dnDWYJbL7GYi4yt7mybehuhne", - "3js25yzgUwUkk4b61NYSuw4SfMbmStoPXMy8ZUp3hkf7", - "3kiAniQf6y9ZT3SdE8X7Rq5jM3MX6BUZy5KDT3wt6zAk", - "3kWT2K2HfxrspLFoJhKUAio3QF85EuTemJKTUcPEjm7m", - "3LtAt3iqmeTgJ3GD8DtCcjkRkJdDKAF42nJytn28syeP", - "3LWv8RrdEyMtePAMCmohBzWAz7fmN7Cf2ctSUxJKEQnS", - "3MdUXXiLWeXQauVSiuGwPjakCv8J5CX5v1fu8eutJ7v1", - "3mx22d1aJLazEutJyHVszdwyLJcrRo26EKB4AWDbRxRc", - "3NchsxHzVUAv6MTGEuAVt8QRdi93uHGNRmS9AEiZkMVh", - "3NdgfZXaj83dKoskxY2LPyQmrjtF3ikCmfCJeKTdFqaB", - "3ndqwmmqTEFaydt6bgTDohL35WJCjv2cezUcYezcHHcJ", - "3nL1oAkcW4M88VG4D78dNxHrqaNdKyJqKW3wbhhBjhig", - "3NtGCPqA5dTucxitLz5KTxERZ7XdVSZ8c2m97TGupV3S", - "3nvAV4PVG2w1F9GDh3YMnhYNvEEzV3LRMJ5e6bMYcULk", - "3NyhrTWkxdLmi1nuW7Xo7tfqSKrsM6dxQkZzhs7Z1JWx", - "3oaf5Y78LHEt38Bcb8bBtabCBySWyyEor7LN8hGwHLLU", - "3oSpYov4ngdWKcZBnxxSPTe2KmeC5s3iKTi518KP9exz", - "3pqniPoVa85STVdvSDpKiaAqvWrMWLgsbJaNos5mvnYk", - "3PVz8crz85wgqgudf6mxws2psgKc4kr51MhfmU6VekEG", - "3pzTi41c6NAbZyTiyPEAQtmi2K5MyWZJMxx6nDvWPgnQ", - "3qaaXFYh389e1Ncboc7qbCWxSQdbaiYuTFrJVYuh7jo2", - "3Qj4rFsMRMsXnYescUVi53kDY4KjNnNy2QE4tc4WpQET", - "3QK8tbsVSwU6xRzLWhVFJCcnqm9WPxSUdaa7cXzBQZZh", - "3QuBhrNbo47ywuK2TmAbvKp331kNDr1up5HM4J6KKYwC", - "3R82jDjQsrzZgQKiEJbKfdCA9ngYQrjZehYuEFmhhfCP", - "3rFxX6D68YhDpF7c6vDt2yhfp8CXXcjNNga43cCJ8Ww9", - "3sxNcHfzE1ygfrYB9xpjyuQ5nBnc1pwJdVCDhZ8eK7LW", - "3SYNAWbZuuWMYKHwL73Gpeo1ySqRSshf5WDoW9vYVz9V", - "3tEqZrbb7xwaRwri19Z5TAznrewnM2m2SCkvSmLztWcE", - "3Teu85ACyEKeqaoFt7ZTfGw256kdYGCcJXkMA5AbMfp4", - "3TQbBx85TDi5uQFLDzjZmecs1esSen2Lh1ybHvdUPkEu", - "3uF82ATbSzKFpAZKQ9LV4BziPsKycMeUZCzaWfL6rSbU", - "3viEMMqkPRBiAKXB3Y7yH5GbzqtRn3NmnLPi8JsZmLQw", - "3viEMMqkPRBiAKXB3Y7yH5GbzqtRn3NmnLPi8JsZmLQw", - "3vkog7Kaki74rn7JFWxKyrWfTEUnp4cLpJyvgs233MyM", - "3W4fe5WTAS4iPzBhjGP8a1LHBTx8vbscqThXT1THqEGC", - "3w6hQh7Ndx93eqbaEMLyR3BwqtRxT2XVumavvU93mcRk", - "3wwYJDVkY1rK5emynSYgbwUy9X3eFcNQiyYxc4Jsd9iL", - "3Wyqj2cgKYK2sSSb3wVv3wJ5yD3yigV8iLLttkZfKn8d", - "3wz211BhQAE2n5fjDQSStM2iSizhNRyJDNRkDEc1YwMF", - "3wZB4hqoLXqBuzFun2sBstu72RgYnR37RWk8YnqzEBLa", - "3X5fSxjnJ3Y626cGNosRokUW3nYdTpvZeheGpSjD5uEb", - "3X6FsQ8awkcU4iXTF82T4RtnTJx9LTY5D3dHK6zDE1Tp", - "3XeDMpzQc5SmrSE6w9nYBXkdk8AzX7q5XohzxmwMmExG", - "3xgtKbSXjtZe7hqxHbK2WLYJGPJw1hfvZKzHrTkygiZX", - "3xKsqGgLMNVazzNBsKa9TPG2Vo5fGLr1xkKrTMVXVVkT", - "3xUTkgPKNJZ3dkpDMV8zWV34BkmvKanguKipv6M9x2Mt", - "3Ye1g9E65wj9wtbTLetQbjsQ6SFj4s7RdTJaxjq6duDq", - "3zAa3TC1Z8KZUmi5TDcQLbXDCETNEdDkcBfKEBchTuCm", - "3zQeAZpvgzhffeSyoZLJUrbkAk6ZjV9H1SBEtCmm8HyL", - "41NQTqFPCwdiiGMibSExCNJ95ALFBkcxJtvQw2S41oLc", - "42oRgGrFtPHPdw28dw9HiJEKTc7WVJh1ND3dDc2m2UWm", - "43h2uYRTSVhMNXKuxY4Kn6T558u436qy59cV6Sz6rdRi", - "43ZCLRdQgcajUq4WTxtTqkqGtpNnJTmLUs4ef4qGKtAc", - "44J72PpPim1PJHge3TwJWAMnuPhwE7DMLaZmCerYEC61", - "45aGtJWVx9xbhp11diPithdQS1E9Hzjm5b5HEpAM68Ax", - "45tyReiehTPZ7rYq35khyF1bnanHPHavNrRj5QH8HnAc", - "462x4mp5aZ29SetJR3oka3d2ARXVKUcs9f9hZsapf7ML", - "46GijDorcsduUvWFNWKAV1yB6XwPG699wS2gR4no4zGU", - "46WCeEExQaEJfatG53qgxMzgPqubbrAvVBeYSyUQt317", - "473ToSs8wTyGd2DTmwb1zNkr7TweNC1Wfui2FzKNB1JE", - "47qmq7tBedjcH2vt8TkANNcPwARqHr5Xh2fJxCkTSV9y", - "486kJEz1XJ95nULg2Ccj9Av9yi1inexzHRVW9UjfR2B6", - "49gM7gXEJEokKHEoUCNve3uCRMAoRwKUpEiqK2nku6C2", - "49Q14TEnx7XTHsFtRs9xhQ12wXRHwaWJ5YSpGhVNhSgy", - "4A7XYUpU2Cvj84fBhkcUQPQMJsZywqgjvD65zSRZmquP", - "4ajWybNN1XqaapKEEiz4MPMyCP7Ppuw7FMQwQ57o7gFZ", - "4AYWAYndF6EsfgwVTrsHLMviNsvuqh9dAMcJynpJk6YB", - "4AZNBZYtjpbJAtFi8cYqy79EcP2qHp4fkLBagfdpvMrY", - "4baXhu594FEQtZsAmHNjNM8K3NxmPNsYCxyPUZnhwHLm", - "4bLyjRauEjdJGb86g9V9p2ysveMFZTJiDZZmg8Bj29ss", - "4BWRooHWbpeBRmjb8y3HgtkMcK5MWVAKce2dSXnTP5Tr", - "4Bx5bzjmPrU1g74AHfYpTMXvspBt8GnvZVQW3ba9z4Af", - "4Bzp9fzcdjctbdo23SCwCEkPeQzCeyTb3WtwiK3KNVRc", - "4cLRyEVzhvt1MKqEeVeVfsxfJzZyUwpJGQADBW9qgwks", - "4cxKnptRvBHYMqUX5hsbEBcj2GmoAxmJGYoqN5YgfUQp", - "4cDG4caeUNBz1Kx754vNvZKa54NwDv5ph19xuNk1zsvB", - "4dT3ySaMTMyG7wssPNYUixRBxfkbWTbnsoaWLzfwUinU", - "4dWYFeMhh2Q6bqXdV7CCd4mJC81im2k6CXCBKVPShXjT", - "4eyn57baA11sgvkQafTcrwJ9qVs6QptXBahf43Li1jKc", - "4fBQr617DmhjekLFckh2JkGWNboKQbpRchNrXwDQdjSv", - "4FZSiJpGgprsVxkzc2F8v3bgnRpk8Ez1Dq7ohXwY1q9V", - "4g5gX1mmFGGragqYQ1AsRpB8ZJvwCoUKVT5LtKTDrNSp", - "4GBSypESidsbB6ACFRUTkwDwcv1G5anashx6UvSypqCF", - "4gEKnFpiJ8XC6DdFw4D65uYQeMF8x7KDqMrBPrDVjMPb", - "4GFicguUX8WDqFL84XWpvKyqm7NXNUg1T3GTiKUu7MkA", - "4GhLBaxr1oEHWpoGnWh3mcRXUkBU5EEQZv3L27c7ohoq", - "4gMboaRFTTxQ6iPoH3NmxLw6Ux3SEAGkQjfrBT1suDZd", - "4GsnFvSfNWzTbeXAPMCfbUPjYmHU73a8wyiX3zrds44W", - "4hDEtsHXAf6TMBNJHogmN5noitFzxGxKAs5YwsKZzrDd", - "4HjA5dBRcMajmaYfwYxqdJBzYbuFxPqjoVjnsTk6Xjqv", - "4imbBQgQvg447bVmyodJYjyM5y6NH865h97bswNM3cXk", - "4Jb1YfUUN1xxdYb28wPLT6A52j459uLNBJaetpk3vAKE", - "4JPnDAjvQPYB8bJVw2E2Wvi1sZZd5VHAMeBncqqt8U8J", - "4jZMrzWGfMHDRkEBqwnx1cPR6uP3i8v2EaKALzi7bYbc", - "4JZsGW4WUSjAjH4joCaAAVnNi5ERfHr93YUDxmHZpDM7", - "4keeN1kQVHQFKBJvZNKjmLHpLvZMEM3rtrVhwM23Sbgr", - "4LyxkXdt9cwze6MkBY71pKdV2S3SxzNBYoUvNkDH9hBR", - "4mCp1G9zmqRH53wX7j17wmZimHbn6ep1NvLmsMUwHjDj", - "4mdxZgQQdkVJvPK8Z8T55sbUXU25ZzjTNs1ydvrzVnYs", - "4MNtUgysSfjwfpgYBJFJQA2Kn5LXPQzgRLnJoCAseKrx", - "4N8tZu9Yn9AkkpJCYVSH2o7jCHMThkeG8SRNc3ThnrFL", - "4Nh8T1d4YBZHEuQNRmFbLXPT5HbWicqPxGeKZ5SdAr4i", - "4NKRcNv3BGZAqHnehxFFPpWdKLtmJ4WWidoPk4hK3UXY", - "4nu5rdaXjhXHniTtVG5ZEZbU3NBZsnbTL6Ug1zcTAfop", - "4o8VRbGZcmiWm4Zc79LsBgDcqXmmVte3kvCroq2zwLG9", - "4oNUWNoSNnwghHBCGsuAaQEuaB6oZEXE2w4VNhRxoaQc", - "4oRsVpbjGU17ndfQVQSFNYRzuj3uETiBT3e1Hz3GHLLi", - "4P5UxtvVBXBmYRGMV1GM6xVf5soMsYaPo5JDMwcWhLVU", - "4pZjWxF6277CRncZjggHdiDN96juPucZHg537d2km4f9", - "4q1KX2Epud4kS7tYuyndLaon1FskmDqcwh5ubxHiSzdP", - "4QNekaDqrLmUENqkVhGCJrgHziPxkX9kridbKwunx9su", - "4QY21MyFAtXbagGymZuBLu3a6wUkFg5qaUDRwYj4Pnuy", - "4rGW4pdnjvMi22PnCdDBGxX5ChTrMcyFSF3T2xHUEQvC", - "4SqdkosjugZVRdX2kRptUng487Uece5toWHZXVh6cpQV", - "4sRKUyYwqmc38TpPGmkbLfjKkyNBGEBaiYJaMCYfkUBh", - "4STBf6muaBxEx8e3wcUT1DwVq5UuXxXYjWPcNXecpdE5", - "4u2qTnf4QVC8PcgNFPBwY2PwdkiMa4jb3KnNZo4zZbtV", - "4uykzcDWW8wnVWMXXgh2RqXaddSVsx8TNvpJV7eACXbz", - "4veSBAABaESW2WpnJzcdNcduopX7X1f63KziC24FhQee", - "4vgoKb76Z2vj9V9z7hoQpZkkwJrkL1z35LWNd9EXSi2o", - "4vXPjSaZfydRqhnM85uFqDWqYcFyA744R2tjZQN8Nff4", - "4WkMVnmyoWuAGifnmqdWNtD3nudHp4hPPqvnyUHLkGWC", - "4WufhXsUhPc7cdHXYxxDrYZVVLKa9jCDGC4ccfmuBvu2", - "4X1qvzrv95EfE6x3i13iokffWBLQGT3t2ZkGaKmERX7r", - "4x7HEA12XAiqjsM5FbWkyNnwKfqzSDHWA1XA79uFpzGJ", - "4Xqmh7JpjaFj5wJ6tNGbEY8eoY8U3fPMUKzfQXcGWiDR", - "4XWxphAh1Ji9p3dYMNRNtW3sbmr5Z1cvsGyJXJx5Jvfy", - "4YGgmwyqztpJeAi3pzHQ4Gf9cWrMHCjZaWeWoCK6zz6X", - "4z755TDizaUVyRRKw7y8DnTnnon8ksQYsZyU3feF6yFc", - "4ZtE2XX6oQThPpdjwKXVMphTTZctbWwYxmcCV6xR11RT", - "4Zto93KdBuynSnyyQct6ecMVxGNrjvVHe4CbWJTtvLSq", - "512wm7UysDB8PNwWpjMBmRgYHdQAoj7o6EDJ9CUyK2kb", - "518q2YT5TjpwZM3sLSTk58VVmdYkF86abh7GGyoUaHZ", - "52GEvaeCcEyAUKrfoPcey6vdyw6th588nYPuCkn3Kxes", - "52MERCkzgb4icyneihfLaeaqhWZYPxYH8fyJLEddnYXY", - "52rpdXBbJG4ChidZc1BiMU5JucsJQQa98zZUEUaP8Rwy", - "55nmQ8gdWpNW5tLPoBPsqDkLm1W24cmY5DbMMXZKSP8U", - "55ofKaF1xdfgC9mB4zUhrffdx7CVoxTbNo7GeQLyj3YL", - "55tZynRDphTaxtH17x87FjcyJjCHCch3SrVxuanUJZmd", - "57DPUrAncC4BUY7KBqRMCQUt4eQeMaJWpmLQwsL35ojZ", - "57Nqrmi7wnUsvBdrkSpyfJHWic9dJqw1KpfgYtmx7XzR", - "58J9ucd9Qc6gMD8QHh2sHTyJyD8kdjHRQZkEAyAZ72YA", - "58ktQdWmK3D3VxX1smCXhHGKdNNEJ93PGpXtX8RLdLHL", - "58M2W8tybgWy6pJVqk7tT7YF7C3rmUxVM4MWN7LG6m7D", - "59TSbYfnbb4zx4xf54ApjE8fJRhwzTiSjh9vdHfgyg1U", - "59WHuha1QunWmupWhFA4vr3WMUe8BLN7dc8HUsJ4YC86", - "5aGEHgWCyHNxCcNMHP5TDddUkT5uXGpuwBfonE13jnMB", - "5AGFPAidurZA45DFXc6cERHsvkdMKohXdug7bBFoCsd8", - "5B5zutCiy12JLoi6urb7uX9rZzwUhYH4VmiDobMB42dU", - "5B8dRstrVg4NXw39yswMdr6ETHCsbKaSbWCAxCH6gofs", - "5BFP2FY7kdV3ogDrKf9UtKphrRSd3kNGC7p3q17i5rSR", - "5Cf18uw63TPsS8XZ2gHiQKzxPh7i5axu6knFfAXFDEUe", - "5cK8WPnW9Q7rfTynaHTGHXHNRyZxHHT1iDH5LyPeaSQe", - "5D1fNXzvv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on", - "5dB4Ygb8Sf3Sssdxxrpbb4NFX9bMrYnieiz11Vr5xJkJ", - "5dLMRyPWx6rdPGZpZ7uuZiqry96dUT5yz48u62Gzugi6", - "5DsrdX4xPok2YNHUEtQsRuyAkDcdSBPXM74ezfRgy8Vm", - "5EamRRDR1j78iE2Q1TUmoDQRw59m2GTs8QJWtnTZsKf8", - "5Fa9zxgMJV23ShcXDYnGiUstjzeTNgeDaGDAYWBmEK3R", - "5fcmYHLur87RDZDmdXi6jDEuWKVeg9KcNHBu1UNqPjHU", - "5fnyGEnVu3nyMrUysGQLXz38QH51VNtmYGSA99197xCX", - "5FPQXMJxXKJmuShQCiTRYPzXL9LBfgphprhXR54pr2eu", - "5gpRDdBffGa9quGE7hTPVCg9zVnHTS26qvbd12G5kSS2", - "5H3sMCaSJdN2k1hyuFTzq2BrZHUq7CinTa82hJS6EDTf", - "5hwtqBGMzoat2a7dzaPXMLKNPZUcsFm2jAko8Kx6tJLk", - "5idH3j6ugKTqSx6WHZax9LmVyu3MQ3sy1zsNqPv9mEgh", - "5isoKqxB8G3CVngTkrHddmvjHhuKBiYZwLfWDufWZtwU", - "5jAKgxnCLVrb5zdDxjnRotwNirVG26Set4ZZ6BWC6Sx", - "5jLw8DGMmjwaCJWbkT3dksXVEdWrXzQtiBd2TfsF1J1H", - "5jQqKbCAeYLiKK4WqppHhKBxe4DzDZMRLLaDhDQJ19F9", - "5Kev1Y8njZLiybgnqTpTnjZ2H6NMtCeSK6J9TeqhyZnL", - "5KFXF9DS2ETQVfUTAfMygw6LNbqiXWXYr4y2k1kYr9bA", - "5KG9uYHFKSmJVgvXys4dKkZ1iVzmsHxDJWP1SsAw9ahj", - "5KK7GDAws7uYezSUcugdVrWNrKNA9ooP4t57Jq5W1mTa", - "5KZRD6hDCZd1dgM9rJLweFFRkHu3qAgBhHgQ96Wz1VSn", - "5m28zJcp7CsTrH2szyNQhygvDis3dPwbgrtYsWi3J4jN", - "5Mbpdczvb4nSC33AWXmh6wmDxSZpGRANNcZypdPSGv9y", - "5MGfrpdVsyifhn2x62j6PnBWQk2c5xTUK1o8KFrwPLWG", - "5MJU7ekXcjCf2sQq8BHUo99wxnPC2w96AizSUMhWZZeP", - "5MNLjn4p1bNUMRc7YP3rEWB5BQbzNsHYaqmQLwshAndB", - "5mwyVeNzQx6CGnNSN6jPMFdui9LDvmFQBHcpHNNvDrMc", - "5NH47Zk9NAzfbtqNpUtn8CQgNZeZE88aa2NRpfe7DyTD", - "5NLjk9HANo3C9kRfxu63h2vZUD1cER2LacWD7idoJtKF", - "5NorYZBbtgbouD3toX3761ZGbaYTWrNSDNci4G4zV8eo", - "5nR5ktqmZufaVuK8N8nNoqVrQqopL6qAnf7YNvsjynhz", - "5nVDe1R4QW8XcaWrDUo88tG1V8CgAV2BqWpCX4mF49TE", - "5nvj4tHGRCRFmTaJfpjx3RUcNPtHv7dDkxMbc3yF8UGP", - "5o2kjsEZDYnWGfTqBJdrBnRYKvRy7wjrniivKwFqyTsB", - "5oBPhPGrCTHta55o8XybDBNTk4KAdAKgaSZmTDdPFpMH", - "5ogMBk74DTpRaEahTtBrrsFN5mcZ2cfmZfPsJMhJm31t", - "5oR5dh1WTi7ACiq8bdYmQN84kDG4HDQuX6cjyJErgGz4", - "5oVky3o3pNbZfWndUBJbxH82ZDqaUx7k1CorxfisKWZt", - "5p3Y7UV2oZrSTTSLJzJknEzqQpetmk2NB2hQEKPc43dC", - "5PLDu8auwqtMkHW9zdPsfUcvyESZ45umFc4r8cWUw3Zp", - "5pzqyoXaZT6ADEGbiziPL3qTfvSA1XuP9ZLXpYijp82K", - "5QhhX9AD3PSKP6eZHLYdFGaWuyXMM3b61vF949edSrRE", - "5qsT9h2TuTMPLtX6gcD2DG6mcZwechxmWhKRFHbCt6Pu", - "5qsTBZQPAPYsCBw9aPC6wCLpyPua7VmK9yFWk8gLQaUP", - "5rxRt2GVpSUFJTqQ5E4urqJCDbcBPakb46t6URyxQ5Za", - "5SAMpCcejTXQMnbrtkNv6nSxqaYgjRbk733QNzc4teJC", - "5sjVVuHD9wgBgXDEWsPajQrJvdTPh9ed9MydCgmUVsec", - "5sjXEuFCerACmhdyhSmxGLD7TfvmXcg2XnPQP2o25kYT", - "5sLRnoek1tvdnJU4qjEGRwUmVNnMRUD3eiJVxPZ4zddD", - "5t5yxCvtHxCkDJCCrChBQ2hdcUrK61tr8L2QRHtbnpCY", - "5TkrtJfHoX85sti8xSVvfggVV9SDvhjYjiXe9PqMJVN9", - "5TLrfzh1tXa4dPu13mYfaX1dB87Md1tzCCofes3VMNYx", - "5TZbMUkDaxxbyhkpgMQHZQCyvHAmsg9ZyDHf4R26qrap", - "5UBdwqhphJ54qRFg6G9iRZzuaSmbFmwy2KyE28JMLbYU", - "5ueaf3XmwPAqk92VvUvQfFvwY1XycV4ZFoznxffUz3Hh", - "5unroM4ZHe4ysnprhGrsHBUMsCbkfAHU1Z4rMtosbL26", - "5uTcsQSrUffYo6RYSWj75SuGMkJ4v9x5RYuQoTc5aWGR", - "5uy7h23zmpVvG4QnFV91ATJzW7PziYu13i2BNev2n1dL", - "5vaCfp7UEpW5qdJYyVH4m93oMzzyzTqXdbr7xLGobY8q", - "5vdpdDS5vvUrPTpGq8zDWmirYheKHq8RWrQfUrbarN29", - "5vfvM4qv8UERxSU4qjKhcyJYgfvBwxM3zotkbyXg5z4z", - "5vKzPeQeveU8qnvgaECkdVdBks6MxTWPWe48ZMeC6fdg", - "5vtNLiiVi7N3WDPeHtaJu4CA1zyXBrdmC41XZktxDZ5d", - "5vxoRv2P12q4K4cWPCJkvPjg6jYnuCYxzF3juJZJiwba", - "5wf29x6Ws3NJRLxrE27cB5xi5ia8DAo3vNyKpX5Yj4dK", - "5WhrU6gqgCwNBW7tkGsAZTB5bno3ymHVrmQb5yyxexBP", - "5wsN9Q4XLXvxjefK2tszV1z8DRKSXyGo2NxvzrftnDQZ", - "5Y7Rq8DBLwmDGgAUPKXyqJ57mRC33krMyH9dzMpuwTxF", - "5yqmdjMVX9F64YuE97neemY6Q1s4MgVaBbJiz9g5qGiC", - "5Za8eDus559NMWtNxwpWFqW4cNBuuVN6JRSCiRqdXhSn", - "5ZimkW45n4mWVCqXsqEEJuJWvhoqZFX7iRBz9jtHW3PQ", - "5zRUbp1Dtu3qQaRVf36oMDaeH91D2ePnc5DEgnh1ivFg", - "63KsHFi8cZ8mYPAa3dRycoDBV1cds3UNGTEijLyf23VA", - "64vN9NTyfwP6J4iTVgQcJKjXmJ4jh5xp1NB61xugEtmm", - "67VDb2iEdx6XjCfBLXhUgKQQjTuLe9X2eLqTq5nBjUTy", - "688vLxT7Gsb4YX9YotViUauLC5aYbnjm1SQtaEQUKitf", - "68qujN79HiknCPBbGESncjUDeC8V42DigCGjQjpaVher", - "68ZxNmvRkaLLeNdqkKWKKSCmFiF28Zcy4xVHN5QZuzY3", - "696mZGRLiSvLhMCSTHRrmmgUvxPEjvBBdETDL4a3PGLx", - "69k73WLdHRge7E3vCUiDx7Dkm1DQSBBGAu9FqNj4AeJD", - "69y24KUYmXFY2N6BMfzL8TfiKjQtBNCCjtnju7bxh4zG", - "6AaA8HJGpYK9RDN5NQjDJfHPcqX63hnw3NXEa9rTXbEs", - "6au2pU33RmTdpoZ9WcYrHnTmTByMJbMMPmZPC7Z454hP", - "6AzAaGnhw5E9Nbkk4e7uhRFEtTVKPYwxWsLhVL8wPDuU", - "6BeAn53Zti3ke5zRm92YzwaaZU5SzMpCmTgkSR7vE1mC", - "6bkTEGxMJf18WBT7QDjs39aEEmN39mQFFQfihyQ2yJkU", - "6C1mHAPxQACd8NNS1D9KpGxqSRUz5s6itsaJx1uteofx", - "6C2zZ5hac7V9KzdwoGeRFjVpAgPPbXvxGrcRtq2Pf2CG", - "6D6puBzRwMwVNZUuEipFycFL7xZgL9sPEnj5p68Tn8iP", - "6DmskQV9ricrKpuGuHzyWmdsJcHPauvbPALdbsJxM9GB", - "6Dr57RWT2ctMt2XiQxj9Nec5mBrfjucfAyh8hWQE9cp9", - "6dr7c5k6SsFRFfmoNqADxZQsvPjPjg4meeEHVX8cn6HU", - "6DrFc9AuBwCe9VUSArhP1bfYQRSYie66pkH6C7wyw5uv", - "6E5NygCNcfyPHkLbHMckzF25cgQoxN3DfMqH9bwyQRpf", - "6EfiVm1bAo8yWgZppb5irTqciv5VC2eoNTFToST5c6Mg", - "6eWWU6wZ4LA2q25v11VkVtD311MruJRzzp6cc8szqW4E", - "6F16m2H44H4LHseHDuk67k2zdEXCWQdGnA2BQ4yMQFMX", - "6fr7ptNzTzzgcqmBDT1PJt3RTnuTnM4v7jfFS3zaaopa", - "6FTLATh7CDdqkFyYJuTR7oFyvhVK6UHUK92fELg2mRno", - "6FWhS2CHjtCf81GMsqHRXQqDUh3UKyyWGF15QGCWWb7Q", - "6g7urUx43pwjUZ9CBD9c76oLQtpHCgCxp9hQhv6RUMB", - "6giEzjcXWwiodVL48LtoFexax73cBorvq4NM8a2xUkd8", - "6hvLbQ32BYawSQobBJ1Sjspb7BBkQ5ueUbh6H7eSexYi", - "6j7DvYDyFTdrK99apFuuT8w2WaeaezfwLDLk8Em8sB2m", - "6JaKmYstgSj55SwwQDihDq1Q251FrL5ev8XNiqFSP2qe", - "6jhfZV63yGmPM4djkHYNZ5eTxmuMxmi55UkJBDeMjUqL", - "6JUvAc4NV51SfX8G9zwoRptU6hw1eC3fYz443Mh3Qj7w", - "6KnzXAhpE6ki8GuNQBqpHsVdHhsyg5csChPGLdkTHRvW", - "6Ku6Cj3Y3FETU6JEuwjpLLu65CnKhi5YGtKdUTRGud7i", - "6Kwr8fUZPmSFNWaXfRL7e7v38itt276DFVu7RiYn8oW5", - "6m8LGKXMT5QrRQdQsQAd2VHpYwJZebbrc48WgkPWeRYc", - "6mAuJ3xKzgo4zSxoi3s4uhaSLh9qqtyZQBhfhJbSaPQJ", - "6MEyD2RCk74jqYDrmuoDqor7KQca8B3pyRDw91ynmgki", - "6Mi3Q2eNUCess79xZJwGMhYYwzNo5Tr24Xbw3QhEWyFt", - "6NDU8PkeQhH8DF5Yw1Cn1AexQoQLnqr13GhNuQL1gfuT", - "6nrkRvzUpTst8teZJawMFFHrmixJ2sxAUxPKrqoGwCB8", - "6oB8HATu5ApWMWhFpE4Ms5XMNcKmjk83VpcND5U1vHof", - "6p9f4oyPCR3iyAW69DjndFuggRt6KFp22RVaywthff9W", - "6PdBqw4p1iaNd3CYg18THHpzDBuophRUk3qSFy3KNTuD", - "6pJAzQhw3MJBbR4BPzhWJk2Hf5p7idivRrepCuh1BrEu", - "6pjd2Dfsv7FNkNDCGhzb8vn1DEmvPSVicdQxvGKLVQwQ", - "6PkpXpQeLMp45TC1PTPUhCpywcCxMcmUXvH3dNPMXQvo", - "6PojfJo3DkFNHsybGRQr3E7DmtUPvnnUdeFFgN2MBkKE", - "6pUayMw7LVx31eA86LAxomnzqktGX4rTLvDzznRHDuNh", - "6PwxMMGLFnAf9sjMHfVr15z9fntjYTNPxJ7gFhkFxkXi", - "6PYMaoJf89uNKjUPyf1eUh6KQ8vGAHt9Fb8EK5SqctKK", - "6Q62YX8UpQKABG1FANUsTjJJdrfYZNEAbZyceuaVbx79", - "6qJPxxgZHCQKBvbGC9zCsuuPtHMMLszVCoiCvEhVULyJ", - "6qPPKb2zC6U9g8pwAGrYJxy9B9noYiKxwS7NnuRPqpUx", - "6QyznogeoYxn9VLZgijxfkFeEusTu8ip7FWHXwGnH1Bt", - "6R2SsTxEK89a9m84Z666c7M7wGcmbwNmTCyPFcAcftyX", - "6rBEm4eWXATTETo1ncXYiAJBLwh1VtMBiRwMLRY75yR7", - "6rDzQVov7rYNcHSGsVcbQny7VYCinkn4U86Cfz8xYQdC", - "6smeNG6M7Aers4Ju1drfZPYBS4WFK89EwWphQjKTMQSj", - "6sSBHSuyRRphvkH4GAwccGRB8HdZLWC9VENN3c6S39sd", - "6t8zWy766tsHBVNxhMwsTGiEYkGtjaZncRU3vcSEYtHU", - "6TkKqq15wXjqEjNg9zqTKADwuVATR9dW3rkNnsYme1ea", - "6tptWLfq3o2Q5M74ZJLpGGpA9jCAScHSaun5aQVTtp1h", - "6UrGCcP3H5REdZrPx9X22s8Pj7q2RzUWVT5LFCLBevZ9", - "6UynSxu2fiY5qU6Ae8cPLxq4jyWVpnr7o4fUyWLxCpcp", - "6V9ymEmZyvpJFpTzMAaSxs45QpoSvNUQRczhBF8mWKXt", - "6vx5vGgqAa9dRaJpbViCNDjzxp6EyGV38YMYbNDqTzLr", - "6vZuaLY4n4GP9DVroymfZ4D1oP6xpgF1ExLMqHQbt32L", - "6w1jYS7vrmprS1u9cQd9uFo58AZYvJ9JtzihmkRPgSz7", - "6W2xi4iCGU8eTMCGtG3DQXgMGurXFnd5iVXCY5Sq7AbF", - "6W3xBXKnq4vGHvBjMNSgVviQ6vqDeWiL4LwnSFjvr8Yo", - "6w8Gxzq1AusnWxrnBH49wkWVemp7MPxXftfyUQy67yJZ", - "6WHCTDvSa47muoyi5zHoKKPcodkftixsauEfDNB9YSjL", - "6WwCWBHYvNXnDswu6qrHbKoXMqtB1ZwRCD2U3oqWbZmB", - "6XSXMyUJnjTR5Az6jQyX4o9bjMXnyt94u5MvAtmrH3dZ", - "6YpwLjgXcMWAj29govWQr87kaAGKS7CnoqWsEDJE4h8P", - "6zCt5z72rfN9sRk2hTgc1LeFDbEBfXYmW6xtSNmgyama", - "6zdz3xCHLqu9uruKskX24eztqWUchf4P8YjY3pMnwCY9", - "6ZEbKFxTjEKGC9HUqzy9z4ccJ8Aq3ktPKEzHGDosQJo4", - "6ZGwooZQdrHZNjGP7Lrye4JuStqeLJf7wwSgLcZFNciA", - "71bhKKL89U3dNHzuZVZ7KarqV6XtHEgjXjvJTsguD11B", - "721wicnref9s6HiU1ZWmYTWp3ZRonzHWRxAPSc2Ceu9K", - "731Lnc3mbXpquV8FmFnTL8EE36uoZRiDMUKXehwZq8x2", - "73YGZpfTSBv7PBLvmgcAwa7K2fAaBoGe2Z9YNWz7J4rB", - "74TbcQoVmGdmdZdUZTEpMaLonAtKTK29GsZpfn1LWxoo", - "74U9LiSPv2gb8bBZSh5uVNf89W4wZ8zs9B8EvRVVwr87", - "75ApR5PzaMtcx2DhzZvkj3MDRQWsDCjcuEzWsygboVix", - "75yzn7njq32yY1ieCZxFNVFZQWtEbQHpaaG6dSZFfmX5", - "779hnWTRpb2wSdqFjduzxeyPk41hqSaassmwPjQDGMnd", - "77uXenX1Y9T2D1pcnHnYsYiwTTHbnzkyrKX5fQFMGVCR", - "787PK2WaCUZCyYEmuYQSGmoxu7MyqK1usn43FfiVwhcB", - "78QcjcDqBqvxrjLZVH3Y7vmyCmNdu7VSVnHGMiH4CpcR", - "79SdgYawG2AHZWRTkvSzTn2DLEznQ2WrBxvi68JMFup7", - "7A4WJBegWKXVMhVoKshm4GzjW3Pb9od9ECWxF5DbrSZu", - "7AbNcvhBBHeL3LFhULonjidYSKKaZzyoiM6dDv8zQpjo", - "7aEnmY6hs4dNHpqtMyE7ACVaMaUuiRxJCJzhWMTCUq6V", - "7ajm6amGXayr8qe3nPYA6j1bPMLMCxEmhNdzgz1EjnW4", - "7aKHeoUDCYbEYdSEj63i9m6vmkXLbiafWxoCvyhcQtPw", - "7aKL2G6UMcXWXrvajhs3SxNpBh4gYxgWjT1HBvr36MEK", - "7arfejY2YxX9QrmzHrhu3rG3HofjMqKtfBzQLf8s3Wop", - "7AW5VGSNcaECGKJD2C4rpRuWpcT4kdAHrbahc7KFQM3p", - "7bFx5g3sh5CqupFYtch3J1RdZBZs29HtpXAWyPPyptB3", - "7BncGLSgSexiAXz1dRB7cZEDdkKey2sK5xiLpHESDjpf", - "7BS1RfipQ7zwuKAdiUX5CNFCKNEdk82TN2C3CmoXR4ux", - "7bVEnUUkMX6EWG8CXCuqPSzgEfhnQarAgiwzxPSQqPQj", - "7C3FrWyhFGc75WgccpnpuuCRSqpZiWpvj6d7U7jScSKU", - "7Cj9XfthjKp4KxccS8tV5RmjZtucBuyyXJDRovLkyFmS", - "7cY1beonNGzrqUk4pNWErm2vYcyw5yyLqwnrEHr6iKmu", - "7D5N7KZFN9hCcc6HmDi22JQaGwozaD33MQQbrkNwG7mK", - "7dEjSFnrm66CJ7Aj5mC1hsYmMzmGgWPr6iZNhcvANZ1w", - "7DU3QwALuHzaDU5YVWK1BgeFaPo4TJ7QPAifNHCHBDBC", - "7DyCSDDKvRe1BdxSyN6Q3bvW72VddJbJXG36Ghi8KRcZ", - "7ED12uoR6C3mr7Apf2x7YnSmEHkApFo4Jfm1bq8i6L4o", - "7ETjs9tfe3snSKSnKqzxJJHmpNTT474TfcYG8MSQnuet", - "7EucomZSKvQdiZLvra8hLszL1kRYiGewxyMJnyyzdbH7", - "7F2vcJca5ewzdJUNcVMKCLVYneq6CX9JFMH1U7JeVG5", - "7FnrBgjPb1y8PNjzRLihQWUvky37F7wkvRb7MUL89Q8P", - "7fv6zGstESoyWYdrfeW1DzN4fabJm3M2mRUVid6bx4EY", - "7FVCgatxKrX34VwM4YRhUVdXsJAoB5Kk3EGWW5M2Nqub", - "7gEoBVoj9bAsuugEwoCzjJvVh2h2kNd31zmWLbPM1D6h", - "7hAddyJcvQAS6SsfRKLJzYPuq4h1XykRSJEUmr64p8oF", - "7hifPeGJ4YFHh935XngjGuv67PHruoBxiqeALMqqjDnz", - "7HSAu6Q5LAqrCk7pt649utsDrrEd7yP5NEcqodFd8TTb", - "7JFfCpPEodnt6SWY41ePBRXR6LUGiKhLSKJNw9ZYjdah", - "7K32uTNK2zJwp5WTt4t57qJMf1JnHBq2HcSkc4oV5sQb", - "7kmwiz4wbzf1kUSZmKKzaJRxybGeDMLSqhR9s2FebhoY", - "7m3rgSgyS4HXnBAc5F8tPY9PTXgB5wLNz4xC8b6XA19z", - "7mmRxJNttYcJVNsJmiLjTHYmNDt32EpzUSgLDoBsTKKK", - "7NPcRcHu3jACoQf54nkRBLgdn7zBbUYhnsdC4VHqBQwK", - "7oQ4anNmvJmXUXu6pkXFb5fmovuPSdWzbRkwMBvHi4yf", - "7qFWjQLAYeSGf7MBFo9LUYEiFN4LpMagwFu4MwAUueVn", - "7RTTKCWBJ2XwtSHkUfpwBTH7SsdKqHrWfnD9Dv4z2Wyw", - "7RUobwC33EbHaWWR2sbdaJhT8x8PpgUoAbJQYrQqrSgQ", - "7S1xGwMrB4x5fwhchayjHojKQoCWZsd5HnRHRUJGXekR", - "7scarR3Z5obfefZr8bPKYoMNipua43K35AJAc1YchQBK", - "7sdh5QHFPo4ktG9SVTPM7Sek1WLZpwxNNHudojYi8dK6", - "7sEpbQB3Dryn5JhQVCGWoGgUfYwNEZzjPNa1Tu9mVa5p", - "7suRNpX7bJsXphHJtBv4ZsLjJZ1dTGeX256pLqJZdEAm", - "7T5ZekSsBSgLNKVzQmCRQ5iqL5ycprREa1tz3GYmb4eT", - "7TcmJn12spW6KQJp4fvvo45d1hpxS8EnLjKMxihtNZ1V", - "7TG3LLqWYn8ybpqAJaiop1bVb5mPWJSDhxPaLzUdF3M2", - "7trWtWjH3cGfSu8z6MgkqEEuCJWN5NhRZBYvbT841Yi5", - "7urBmScRfdSH9CpQ2SAwfmvGXp59nTDx6Bw16USJVvGa", - "7UUFbQSderHWPqu6BoezL27ymsgrBbXSi3qQHAozwDtP", - "7UZAaZTjnsFMze3RWtzpxTG1CiJenrvPixvVxW5xSicN", - "7vu7Q2d4uu9V4xnySHXieeyWvoNh37321kqTd2ATuoj6", - "7VV8eZcVAN79xoGL2eEAj5sXVbQEsiqiTCZcbjisjXUx", - "7VVYonADe1jj2LtKZMfTKNPiK7gjVRDsX7dvA4BXf9sc", - "7WgNDqtFHr1hLYo8wcw8X5uCnGwDSYQMz7MMKL6dyLLt", - "7WL3m8c51RELcLyq5AbEA4jzfdiXerGym3DsVH5LBgua", - "7wsxae1rHhA7x1329kfhGKzukq4Ujhw9D241ziBxdKY7", - "7x29aMXJ3kxxTXeU7ur7NpLFWCmedz7LFVo2oUqYA7tY", - "7X3csFXUN2AZph83GC2FZCpkCTZXfVWssaJ72cpwG96w", - "7xhwT3FQqW88unUPfVQat5F3koUTPSujfwaT41bt51qc", - "7yiFPLeyH2B2p3xGrr2Y5nmk8B52nEaa6j55Nk3u6648", - "7yzVecfpWupdJwVQby3inMggGSotFSnSrhvPGPp6JGdU", - "7za9eW1e6a1zZ7RLCmE8uGJoNZ9xCC774QXM55pmUcLm", - "836riBS2E6qfxjnrTkQdzD1JkFAoQDyUjTmzi38Gg84w", - "83PWQUxkBDrTJmJeFL8VUah6BK4p1JPGdXVuJC9Vf2Pk", - "84BoHfEzq1FccYEMZPeuTwc68DQC7LS6Bm5dRMsKypA5", - "84GZWtzfKYX1yfstmjA9eUEp3RnWys8DmsPjsd1ay7wv", - "8641M19beXr6FB4zaf6GPYdLaV695xikBLYFYTVEBZdm", - "86hxQGfre1vvVsYP7jPBka8ySrECZQewjG3MfxoCoBYf", - "87VQhN7dUfS9wacre7vqRm561bNUk5PwUB8xmroc2yEw", - "88ms3Y6Z3pNaMrYY4zdUwHp5K12csjNeffomBnAdyaBr", - "896tvc8WPdR33Q5XYZRxPQkRZaqUv4Mtr1kvFhYPFao1", - "89vXkL62kciXTe93joRCGiP6xFCHrNxYGJbshoWoTut8", - "8a3rCvLRcSMGqQvzoVcHYuJptd2o9sK2rt2CKfTtbGnE", - "8AgqfNWYTzmtoxRAvqFB39Z5kdhoW6BV9hYjW8Rs8NvF", - "8ASvX43WvDF4LHe2ioNUbn3A4ZRD9iC6rsxyjo5sVGLp", - "8aZ5CJf9qYnQtT2XYuDKASj2pCiPwhWoNsc2rBqc9s1n", - "8aZtHhTNFhVWp4fV3dUfBwsKKBjqzHDwpTZRbpeqo7vo", - "8bn2BhTzfNEQoMyEPJ2q58hFzQY8GxPkLRFWHMWksLet", - "8Bp1GmdCguUrbJbrhFDL11ZddgC83cPcbKEUbPPPmxsj", - "8caQuNVnmywtQnKWv6j8MzzJ8mrLwJkeGcKEtkQkoFZA", - "8Ce22R38MddAZSpEhLC38BqUEzVAcZh7h9MgfVCWibN3", - "8cRQ182d1Bai4z6BzPBUk4WsByphHgnYwWQ6aju3FeNh", - "8dHEsm9aLBt7q6zu3ESfRXkS2eCwkbbzzynfd2QxDzms", - "8Di25FopYs1crYkwwrwuVJhuEkGj2rSCjcGXyZeBGttK", - "8diJdQj3y4QbkjfnXr95SXoktiJ1ad965ZkeFsmutfyz", - "8E9KWWqX1JMNu1YC3NptLA6M8cGqWRTccrF6T1FDnYRJ", - "8EN5Zfv3gX46oAguTj2Gp1b8rmmL2mocsHkT2QfgorVk", - "8EqtKHaSgPskksNFSC8oWzSMT2mdSMMtNjGZ7E3KHxSn", - "8faCuTioHxq7DYADQwQeAHaKXjqBzELCgUQBieXhmKGb", - "8FaFEcUFgvJns6RAU4dso3aTm2qfzZMt2xXtSgCh3kn9", - "8fLtWUfZSpAJk7h4XhvM6TqGjXQxiwzWkymxmGtJoGdu", - "8FRFYPcwBan1KBKR6HuPy152L7pr3ePVYVxXXnWzPjEd", - "8GaMqVpXH7JuEs8D8bdXpe7ztUasAP3wdEXpyZZbUJeb", - "8GpsptdhGCGybKqEw19pVBZg3gMaopiKtRMVzJFBddfB", - "8guxGZ3yR7L2pBtXgoBnPpq2RE4GM5qvK8UaMG5YXds7", - "8hD1AVXPYCCrSfZGQKc56Lt6zuSLrFxejLFRT1SN2oXC", - "8HkuMwe42b1W1xvxhLoBGgtvM49FtxTFjk4JgDpLpbMq", - "8hpUJeGB6BF1JTZcbiNEgw9w9fdQ8dEi8jF4ohapsq3h", - "8hzgFMZG4WqaaMZ9H84J9fvcxkYDPYnTDFznx9mxHWhP", - "8igp2RrQ1F4drmXGpV8qNyJL25Aom31jAGJ55avPZLc7", - "8iorF4s4S4NYYEMwGNJZqBbKoMePdoyYyrozanasEWyZ", - "8itTkbGjHRAx3cum5TD7bXaubmEFGxmKxqe6STrVqLdy", - "8iZ1Qk38z15xMW5ATSPbb42pC7FJdFj8NtbG7uosNdXF", - "8J4eQKseuoL1BT6rHSZHNG82U7gDorjy6JuqXqEQSswe", - "8jYnpEZcE9SUYPuaUXA4TMBWn57G1pPecRmT1fLssHqs", - "8KKQ4QJ7JWAosHwL5pmjKpYWMNSxqtQjJVes2hQezNRQ", - "8KYQAb2TqCq4Tay6rLTVwWr6BfSMtSmn6E2qosc3xm1f", - "8L1k1DCCwRoZVEVYZcUzLht9SxUBhkNw9fU5PGnZfw9u", - "8LknwWtMatn1uRenrXYzJS7MxQJXZ245dqTuQiD7wZtq", - "8LkSKTrwqFgw1Knh4gc2BFYb98DnUJvQAxhT1BAFYh2p", - "8LSwP5qYbmuUfKLGwi8XaKJnai9HyZAJTnBovyWebRfd", - "8mK7gCU3DhAG3YQrSN2p3HDM9S9vSd6wddhHKsXyKHvv", - "8NEL8uj7R7ep4qce1BRAoHeETnCcAojXRxAjdzw2jRdv", - "8nGsjSv92c2n35pPcxZUVytPTpD4WqnZ751MeH42whqZ", - "8NgvLoYGP7wyramK2gEzS4sj5UKpRVHZeTUSUvMPMna5", - "8NndwQsrH4f6xF6DW1tt7ESMEJpKz346AGqURKMXcNhT", - "8noQwzDhpb67yzfREDKvymKWtSdPZtbfjm3pxPYA4bag", - "8nvD1CUE48WdcmRdvbyWcM5LdJKRTNP3tXT6Qp2CSND5", - "8nvhPfZMet1yWpYzrEJcaXjc6AENvSC9AcwRrXJeMxhK", - "8onJp7KyshoMcxVm5CemhPgGvA1hdSnHbcjLCvJidV8o", - "8oRw7qpj6XgLGXYCDuNoTMCqoJnDd6A8LTpNyqApSfkA", - "8pf1LTFXYNmvB1esMKvqLq92KZaAt2ETe3pGNxqy2pc4", - "8PTjAikKoAybKXcEPnDSoy8wSNNikUBJ1iKawJKQwXnB", - "8pUJmSJo9WXWVz3uf9rUmvQAxnbuCF6gWNeebbjGdyD1", - "8pWmLkuR3yio1Kcu1CqciTPmPMTiCf72h9n6Z1DmQNgk", - "8Q4HYJH7MfjsakrFG2F5skB9eFc5mpBL97iL7tfCjoPW", - "8RsYRsi6f3hiK4EhyLS22Cy5KkrNbuidVYmsaYR1Xx78", - "8S4Xb96cH4sNrnKfMDHd4HR2bmjWbeUeo1o6yJC6ZGkY", - "8sJbSYEP7HtR1VGwobWNwrwFkjSMoPZU1hMkPzJoNApb", - "8SQEcP4FaYQySktNQeyxF3w8pvArx3oMEh7fPrzkN9pu", - "8t6UUXRkQTBpanRoMjxNxio1baXXkEdeLniCVJGMdzLJ", - "8TBZGt7C7QjyXia45cuaRp4rhQZ7zLTZXY5ktiu28U6V", - "8tiCet13nwqVRtG1UbW5Lf4uuj33X16JnHPZssfvPXpE", - "8tk7QMWkXBbzw9AJJtLkrdf8ZnEQMiWmgXx2prk4DoQv", - "8tSzNoKE2tHYdTpCQB4apHaes2YWhCjbo7J5XCv1ULZ1", - "8uJR7fEaTiriYLe4YMFkeeADdRkexxm8jkFCGRjPBvJD", - "8uvRcrxAx5e6FRzLzobXupokSLwF31cPEkJV46LxyWuQ", - "8Vvc6PNQVbGAXiHssGez6a9ovgu6eyEp8PiTijfzE7nX", - "8wFK4fCAuDoAH1fsgou9yKZPqDMFtJUVoDdkZAAMuhyA", - "8WjzRz9HM2bWBopD6UPbi3swyRE5kk9aJojhn6fBKTJk", - "8WqBgoVXkVggLVuvZuF5wP8taQpzTuKGoK6brU5s5Hh8", - "8xsMN2rQHdmZJ4T829PAYGU6hdUivRU8c8X7jH8zNqmg", - "8XvoJswfYCxWf2WkUmNBjtDWwonmKugYhxBruNpSfS4a", - "8ybtbfJ6rHeU49gtkQUBhAnaXBYGPdMk8dd4VCPmtbGz", - "8yHavC6E35srdiEfWMyQTbU3ahsVheYQpMLDGHzXfFqq", - "8yJz6fotCuDhpQ38Hn1qFyF9zigwF71ENtd9FwkMwwWW", - "8yS3Zc45xptsaay9iaUSpfdb5gaKcQaKAShVvEUFKpeN", - "8ZgmpBG5ixt4LVRQEK538hsKTsJBgmFFH5L6X5e9iPTd", - "8zH1mRkic3WDpUkSgtq1geCXXh4CLVfLrEi2TEqdTgFS", - "8ZjS3d1bQihC3p5voM8by2xi5PoBNxzTJtaQ9rvxUbbB", - "8zYLLHSU8URmRaAyWEY2H7uqUF63uezRCYpzFFkMG1AX", - "911tr1Hifn3z2opEsEEhxFQuJzp1YNM9QMkBQspJviWz", - "91K6thzfVGAQJZkdwEdMYDA7sWL3QJ2Bm3PRXHXkq44R", - "92ZDWNRurKikxrCQcfR9jMMYmqWksgTvSFFJ2Pa5FsMv", - "93E7eWXX8pVKLSrbBx13VpvDtvSU5PJs464uPoty9VeK", - "93g68j8QB4ZWAtEbvL6kfy1X6k2izXosDiuCfPPPYdjx", - "94Pk8zSFvQTvrkwBkMEHzjufx53w3kX6MymDx2ayH45e", - "955xvVJ18xqHdshcMdvZLM246fVABJn7Q8DfSEpyCeLe", - "97vF6NK1NgmvMunNw9QL6ne9wxzUQ5RLAJqWxmDSkKuH", - "999vPueFgE7LEjk8awARTr1MVN5MMCAhaMph31EHPwfn", - "99NHmMDJeSo1AM8dg32nTokVRXByoJuA2gjDUDfiKHem", - "9A1JePcV94NNZSPvzWvRGqiHhPwh9PVGytV9HyEdxHbc", - "9A7aYiEPK5ymzPjniabXofR7jyEyihGAANakUf5AALT7", - "9a95Qsywtw2LKK9GkiR9dpTnoPGMVrLBLTAMPnaUwDjY", - "9B4oF52Web2deG8jdbNbBuM8DjiFyLYM6CTid3dmQkQ6", - "9c2aGPBPGbzw1yeweN1TvC24uEV5oUaGvWfFNJif6npa", - "9CjCwpFfvex43ZrxC8iW26y34PsRbDsF3Y5fnf9iQTdR", - "9CpQtpHJ7UrsT6R27RECtE4dWWBAVnTcCTXj5HkbGJQC", - "9cZua5prTSEfednQQc9RkEPpbKDCh1AwnTzv3hE1eq3i", - "9DBdgP1ggAWJULBJXBPMzWvA539BhGVgTuTfebXhfynG", - "9dCMmPpfNuWKyZ2D1iRstMCc1rhr2DbHVFrZ9wFncQjp", - "9DgTEERummZyV6MVSTmC8A9ZULgnN5Yh7VHjP2PADrws", - "9dSTVY7hXEJsqExDcD8vYMAZpJ5mt9HBMPwRe94nBwny", - "9fMqL641B7nQZ1xktU35qXuFESxMB7pkqmqVANtovzmE", - "9GERkwr654jBUn8cvDydFwnTZ6v4MZbyvp9ZKhRep3wU", - "9GGe8sYSRWG2QSdf14V5cKT3wcFgU9C9114BAVVPvHwF", - "9GMmVYJBw5Cj58P8QtXtesyQUtA9GyecPb6kCki7QSo5", - "9gmnbM2GUVXiTfCg1Pj3ZTJdqyKdS81kjBWwwnZbS4MR", - "9gUMvQ8peCVhxU8ut4eyfzyTZZmvBUVDWw3s492yWNYC", - "9hedZ9TnXRLHipwYnuD8DdyvAwE7sPs9qdqNwjWvV3YD", - "9jAhC6dhjVqVA184dVczcBAar2GtXT7D7LwtXxLji3Re", - "9JKQiQqWkkUKHqnR73MmZ3kdiqQt7d3bEvy81Y5rv6k9", - "9jpddNRkSJTpD5GJFXocmLsP8JUasJzpwgKrHrLtA8a3", - "9JvKbbmSH4T9MuHfpWmb5osoQ59dSnjXzWbS57N9r3bY", - "9KCFj7pL3hzyCzhgiy1Z9nMxT5mkNBgm2QjfbX4nXBPi", - "9KJyBBRfCt29mR21aP2NZHuyvZnf1VjSSB55WPExRgSJ", - "9kkpTAQfndU5SW5iVbG4j1qngoUh59Jwqndd3XpkBzzm", - "9kKpZomqGpNYRPa3A9o7s2SKZVeHKFCWGt3GdXxbbymR", - "9kUAkfKvczyRJMn3cRz7SVnbotSdiTVyCFXkX6qeXmXC", - "9mbQ9mrRjBGiUVnz9Tdf7PuAkWomw3GLZ6Sup3R93Gw8", - "9me8oFZvWuc9cjBuXiW8YDGGZgkitk9GTKYTNCHaBQaF", - "9miqenD7FrGa3a4NNP6ygmYbpxtcAmW3AukuTUbAgG59", - "9MRUTN19MtA1matBH4ddgpS14mPAdeCoFnsLkaLxFeBQ", - "9ne3MLzrzESX4fa7cSyRvFsS9EsNCVfPRDgAXD1RgVT2", - "9nwweyAkLSXutqy13N54c4DMyvgehnkoa72EiwtnBqzB", - "9oG814Uhivn77HToA3V4M755B6Sthx6aXf6jDG7Bwjh6", - "9oKrJ9iiEnCC7bewcRFbcdo4LKL2PhUEqcu8gH2eDbVM", - "9oWDUVn41kNZuVCQBr563sgbLXGvZULKuMr74w7NSkz3", - "9Paysbs5evoh9BiWiS77NNutMCG9koUK2xyAsJm89Rfh", - "9pHNBdibr5ukpX28foKK3UfCMeaB5GyAuGcHyJ5DmUAJ", - "9PqR63RosK5siiSNvHtQMyEKr3CvJt1jh2qxoVmghhst", - "9pZZWsvdWsYiWSrt13MrxCuSigDcKfBzmc58HBfoZuwn", - "9Q8xe8KgzVf2tKwdXgjNaYdJwvChihmjhcHdae7c4jPb", - "9qpfxCUAPyaYPchHgRGXmNDDhPiNmJR39Lfx4A49Uh1P", - "9qrjiQG33wuqBGd9eWBevemxuw7FkY5osCxwYQt6SmhU", - "9QxCLckBiJc783jnMvXZubK4wH86Eqqvashtrwvcsgkv", - "9R7NanMZerZE5kwyfZ4hxo3C5aCNB3x463i5XtLqVEQN", - "9rGfXDukY86MrUcxZNGq3nTrUaQiE917DMQ2EFW1cbDL", - "9RLnzRod7LWYb3nemb75vKhEBSsGqS1uHeuqh8Xuz9B2", - "9RUxQquaeSkuwb2qFqenPw63qXLypEwMwUVNaGHzDifF", - "9SHZFX3LEuL9dRpCgiETWfakZU1ZaXiw7aaeTzgkDzEJ", - "9StH5W5oei8tNy8vrFeu2443Bz52Xr1w7NBmes1xnd2N", - "9SXpQRC2veMSkTRY1G2vLktNgc3Bbw4Nkg4xK1a1aVjH", - "9TA34Aso9JfisCAsdqtpJ6cukxhDdqyE5xSYYvxpCM6H", - "9tbzUabDi5D62Kkpd6oQs9r28Ts7TFJHLvx3pFJshZRA", - "9tJ8BjHCSYxVMJZNvFLRJj39QPssKoTc2h7Fev9xXTPD", - "9U4fqWRd3kcUHEX2jt1kFwF2dSXLnz9RA6B9W656Skbv", - "9UfKWtaruM2whJNqLLcrxKrSuS3VcVssdbTyNvfQCUpg", - "9US59KW8j31mxr1opP4fbg2j86b2p88DDKhcSeyDznnA", - "9v7E6oEm1V86hjTubtBon7cRYPvQriWZKHZEX6j92Po4", - "9wAkySUz2KihVRMUs86DcTNqPqtdNYVHMwFxoH7xbbiM", - "9waRyqWAoP68etU17DdWamgpTnPb3skY7Er9kRZMzCfS", - "9wSnV8sujWbGrg6PL9uoRLGPiWRL33VMqHBMcLYeCAfh", - "9WXjR7Ea8hKt6Z84EGENQvGR3rFsovcxDYu61TJFcWJ", - "9X1qjnyb5CfMkGfEnuRZS3G58iyzbNZCp27RpiRVAiV7", - "9xe4rcxYUe6iADdnvLkWn8K26bvyWgfrp9HYbtwR2sPs", - "9YHpZqGdwED2uAxZbgixESvavajvuHyVZJKbVBevjitB", - "9Yp7sEu3ecy31pKgQkCxrUWMsXiorGsCmxPG8FNwnFuN", - "9yTy5duSRgxznU3mAfQp29qu7Q6sEQ5B54CedveiM8ru", - "9YVpEeZf8uBoUtzCFC6SSFDDqPt16uKFubNhLvGxeUDy", - "9zkU8suQBdhZVax2DSGNAnyEhEzfEELvA25CJhy5uwnW", - "9Zqcgqref1GnwwPNWcXaK88qib5hKqRMaoQ4257tvBpG", - "9ZTaH1QLsw9dcdkG2ZbtdbfzrNVyjmM3Vqxp16PDU8yX", - "A1ieLrRfZyrRQ64RoGVyVQ6zqRhnQKQutm6kRGRPg6ma", - "A1voPbfnmCq8UBNQTBKnZ3Xbhs2x4cS2Gx2b2wJtqCh1", - "A2wYfDhhcoEvm3M3oehAtFdcwdZcxWvWAnk4yrpzbSS9", - "A3zoxWHVyqHui8y3Z4rKyqWJTyr78tusgAEpAtr4ZEfg", - "A4Bz67GutEFuHpoLLqfvqjU4PgwKkff4uNjEXXUomm6z", - "A4Kg15NX9i72WeQiH3Gp4u6QceScodz7CrkVdD2xhtws", - "A4xoiWbs1GmkV4p4PXkBZWM5UDfJqXx8z2sDmHP8FmG3", - "A5hMwgm8QfooAuCMw9Rw2S9vXbBwCknFMhhUwKKHvYeJ", - "A5mV39Cb5d6gbrssHvaYjGuurWpUnRGfMMtST5EKxx5m", - "A5oH9BPo6PRnEHmLnhtyN2YXELnbTotEUDB8axHVBcY4", - "A5TXyVrR7WwfNf2RjoN1W4Dw5CuuMDiLV9e77pWhmwAP", - "A6RXanjfgm9ivaGUFvjDHeSAe6BXYgJsX58UpiNF7TXe", - "A7zCq95mtG2enn2zWxNyVDvhU2EsH8T9oWHs6jV3rtCH", - "A8Lv2ZPKKSBFiAiepFsmCBvWEBSVGzuKxSLVt9z62Bqt", - "A91g1Y8xXFEvCGg9afjTn222JDuY7iSVmSg4fdbQEB21", - "A9CwddX4BA8AgPCmcHKAEZU4JDFRzruMFytr9oo5ZzPv", - "A9qeyUzZoNXJQPe3fd3QgDujekiLg9Fd4VLX9UsSzAn6", - "A9XUvhm5yKVs9Z3tYdyiAYRx9mNr2rqnv2VkY8D1N4uZ", - "AbF88hkkpZ28VaT3vYn4xu5CeNC8G6Dq9cc8ciRR4fY5", - "AbnagVJhwwM4wDuZbvoxWeofdpSWoDMhcmZCdCrxtCkN", - "ABUhDLm3Y8HyLsmua9Xj9on87RyiEsw5j5eVVZQVw1hT", - "ABZonS7EB42XZFg66md9KnU6Tb576jGvxu9AxA4fFuQz", - "AcjhWohnu7vYMdu4Yha63XZupqMKVVnrWmt1F57ScXhG", - "ACPgwKgncgFAm8goFj4dJ5e5mcH3tRy646f7zYPaWEzc", - "ACv5dTk7THbmUpHYGhgPzMhWr7oqHSkuPJpa5RfvmG5H", - "ADCqmaUWXbShzh8GJN1WeaUzy16y2yYEdodPDcru2RUN", - "AdKv3SFdhSZDfjUVNKmLAkWE4NPa9sudvkJ7HG1WYm9i", - "ADriSmPTSeyKwNCo3geTcAY31G94mHmCfRfrJMe3DmbV", - "AdVKEVMZSd6VZ53PYbw3PSaj4XzDjsNoEg9LwDnyWRE8", - "AEPNDgaApdcfZEZpww458Az9i2NZrwxsVCdiUih4EaRh", - "AF3h2gdkGYndVj8W9qQN8jA45kQ5RB2WmoAQN2iBk37c", - "Ag51oCkwGy5rkbGEYrcP9GDjvFGMJrEdLxvedLSTSR15", - "AGCsyz64NLvoDAG7Mi7k3WFbkMjRDCv158Q99WGGvKNM", - "AgFQkQe2Em2GUkDD85qPmHrvybnaXKMa7anSNdCunnM4", - "Ah5arzkbkHTMkzUaD5DiCAC1rzxqPgyQDFTnw8Krwz1V", - "AhT4yWiSg7nnEWQokWoGDz9QPURwa9sEHrPkidC2PK26", - "AicKhNhJmkdqafRDjKLPgVqLzXLzJ8pS6aVrYrRkq1iq", - "AiPN5MwTHxRjG4eTQ1nrmxERRj4oXJURHPiTcNpVYcmk", - "AiWqv1dqsbvkUMec7G4DmM88ka7SaoqDPkn5U2iuvqnn", - "Aj6cb5bk1JbCYSHzNrV7xCzECWZY6Ys3VRTNw6vx2XWp", - "AjTrfjYY2SiTC5pLJXwNXpcP8q549YQ9VrPAxzjqjUaW", - "AK5hfHFusiS2y5cjqZkiyUyAvH5qfidQgrmCccENnet5", - "AK7ZZx2sdo39coZN5FsPdae2xNGqVKHX2TWJixmY4ecX", - "AkkJv1meyo2Ax2XTXEXWpvHTh4F8a68Lja5dx3TaX47K", - "AKqueA5Vfmf6BWTXuPdWxrYCDNPGi5gDLrNpdc1CSEzy", - "AkVMbJq8pqKEe87uFaxjmt35tX2cNhUJTJwv13iioHu7", - "ALPXVb1A7C8EkR7NuKy16pXcBRasdeRNmRPnWGQHpe7j", - "ALzqkbSgVaQz9nn5xh1BtEsey57otKRyGmaSLhwphYSn", - "AM6BNu2WZibZhYYHNo9ZWxmEAB7PhjNQBGKAhhN2VrFt", - "AmNRXJSSaGJrXaYBahD1PBoBR2ApkfLBAJ7SiRK4772R", - "AnMbQV5XNUEwC8HYX5wGkfmM5vo6eCkFUH29PvjtUHWM", - "Aom2EwxRjtcCZBDwqvaZiEZDPgmw4AsPQGVrsLa2srCg", - "AoUwfPuiEek2thVRDhMP7HbQb9rguyab4rDiz2NAfwwA", - "AP2ZiF3mdoDsVd9AdzJWRUb5UHHoQjnLLPXn8rrkERGc", - "APjVTcfzJSzYEkBddGFN1mtFWb8jDzogpgUz99tQW3Ei", - "Aq8yWGbM9uA25KDKsU9KPwoPEuquP5vTqrYomh8VK9XL", - "Aqh2c1x2AA59pek7pz8PymDXzq62qmNiQ5GXhpWq3rNr", - "AqhSZXj5TePD1E7d7VrQ5JhBdoa67Kz87kLQXPcfbwaw", - "AR5Lgk9sgoz69qGBeeTiMyyxZdhvCi2qkD3XUzre1Uvh", - "ArpeD4LKYgza1o6aR5xNTQX3hxeik8URxWNQVpA8wirV", - "AS3rwVs9WR8HTzN7GA4aLBs3JjWjt1yKHfSzmwoqp2bY", - "AsvCrBKwz9Lj44Tp5zkhZabzR4bxE3HLTobrRRGQozcn", - "AT2N17bBBtTAu6ombzhiLNLc8JinjMXmGMzFbxt6AvwC", - "AtHoh3UapTWEBsygTDXNQgphTHcqTj9g4RFpbvPTBDND", - "ATzLEsaydfvFtNBxu71zBVpLAtdszhbKjCN5fdStJbUZ", - "AVAMqDmPX4qjDZYc71Hdh2ZtjhGrGsT1yv86hAFVNt9u", - "AX44APbDNnr1J2wqa9yRQyuaiJ9NWmuEjyK51LiBWZWt", - "AxBt2PSuKyxj4muiCyNqByX9uwMG95CFGea8LcacBwPN", - "AXwviAZcTWRS2Et6BuFd2dEVhXFWpXi2et7bBN9CABcD", - "AydLFeGXYfMTqFDtcDVrVBRijeoHa1odeqHm7is7HuuM", - "AYEHTBfsPvdGxkCnrMHEu1nTziUJB8Qnhjktph5aQvrw", - "AyvS9yc8cuHM43EekkAd3kx25iGZvq9axPhHPvzre2Ym", - "AYxCoguM1XJXcd5e1bYVQB3Tdtu3vnT5iubjxgwvzNK6", - "AyXMWbdxpvDoeJmueCBA3B4w9VURpiQu6pbjrwM2z3kR", - "AZFkNiUSszcpsTSAmCWFTcLPe7iQf6sGp4ceV72JiCdt", - "AZq4Y8BQYmqfav53bWKhqNRV3X34UJuybPXADVi67AGg", - "AZY3mmLS39SKps93TrsZoC9nT1nUrpYLUmQWzbtgyF4t", - "B1Yd287CKFxZnZXMvNjbM9V61kjW1agupihzR2xoMWBt", - "B21L2hCrdE4SDhRi2fHKohfSUNAhoLeaWfBp1C9HdF6Y", - "B2UcYy4WiS1fSYKbMPeAKZoCEzgfQKKt5QBAA8NXLvpZ", - "B4xFUYq2TDmz6PsiCj29vFyvmYvqTRAtnhQ3uSmxQVFd", - "B4ytRaLo8YysM3KHvqPsX6NktfoeU79jaQ3bsZX7CGSc", - "B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY", - "B53tbis1864ZZqg9BBdXFAkDponmVvKHwHySAY2tC8gy", - "B5FNFrfrrfpBggFBp9h6Js93mrz1Tham1z1GgP3bDgNc", - "B5WTSSyoxCpkp5tqLH4x479aWFiMoumXkbf6UCiUX8N2", - "B6eeWqfF19AGj2HtEk6jzSPEvpnMZjTvbyh3d7HzRBeH", - "B6PJC25oDXqzS1hhnx5RLTp6SAdQvctrHF4Juyi4pCWE", - "B6ZramCQhQWcq4Vxo3H5y1MYvo37wRZiAwKk88qaYNiF", - "B75YnUyemn7ixtnUtq4cDUVKrFwQmn8J2Er85ypcEJ1c", - "B7QNbMjAsaZDvNLVaBXo6Z4Wg7tKcESqPY9tQrSefvBy", - "B8T2dbvYaM4gJfpLLbuBScuWKFhnG6KspRK72v5D5uoK", - "B8wQDRb5JLuXjJhAtmY1MAQtLjWQySberTN7wLUHmP2B", - "B9FoWJeAVrDGZbSzWYxsbwGJKrwqMu6vqJHr6JmRdCx3", - "B9gJJ4vMLJvnb5geZjU9PqhkyHX4jESMYajfcALQgRry", - "B9jApJmpNnEpyweF1AApDumzJV1tYxqwqREUt3pJPnJm", - "BAFFC9FVYiK5sezrZc2Az9YZyTaeawXvKLG86FMbakxb", - "Bbe9EKucmRtJr2J4dd5Eb5ybQmY7Fm7jYxKXxmmkLFsu", - "BBvV71ncxGrMDjmKTkcvcjipzu3bv6ExyVPPuRxAPtrC", - "Bdd4XhquueXBB7aZXVYUn1XBdJ18G7Wx3LUe6aKkmXEV", - "BdVXDJ15krsj829E7Gwou8McVYmVKTsPX3EcoBWPoHmM", - "BebUNmLyM62d4BgE8N88YsJPygWrCWSNaCeq5s2U8uzC", - "BEFD2nMciBXpk43V8LPQ5D8NAedUzTswMD7JrXjQpQBP", - "BEq8K2LHtQdNGGURvpUxbbcutFHWQ1YATAvujMz5ju51", - "BerdkMBXBVjUoKUkAuRn4DbadZpxFCB5mSBDadr8GErq", - "BeTwHdCoNhXWBeKnGxJpt7VEbkuzJnwGdDG3ctpBgmPb", - "BF1f26A9FdL6uWSajjTfstnLdCpynXGVrAEzqUyKXJKd", - "BfFiJgrPfecVSMTn1ma9UWMbqcFMftrxzgVp63TFWvV9", - "BfjmopwTknigm38Rj2synkw7mNTjgmm6hsCCb1hQetAK", - "Bg5j1Qfa2SEmio9U3UQKMtERNEjpqvushEmJMAi3SG4W", - "bG6V4uMwXbDvvGessojvShNU2YwUoWy191W6Yr4Jq8t", - "Bgp1oskwwj8mQe94U1Qn59BLEbqRDk1qRgD54bz2fTcr", - "BgrS49ViePLQ84qwwSc5FqC9rpfo78jUUZU4Qbmsva8J", - "Bha4mjHBAS1yFjvjPWWY7ht3jMneu4Lezq219pdU9dFu", - "BhbARoxdh2MT3vb4awXraZFPzSwBdmF9pGgURKNsjBqC", - "BHR2K2tpc1fowNyUf4PfAumc2tfaT2SpvQVqmmpuN6tF", - "bj53eWLx461E3m27qmHGtJE4NZxefhvZUoewioSavqH", - "BJDPVva3kGqpwRnsPFNw7pJgwdaVwqLTFLgbeuBWiiMa", - "BkPf8F1gAeZ4kPmTBSNgg1r3vnYi2NsU1Vfv3swkyBMB", - "BKQq7feS56yp1PvAcBQjb1zV2XYtASm8EGTLy7eGq3bN", - "BkTtw74AC3rDKUbFboQaRVnhLEhsUrchotzSvuweaUCH", - "BkZue4zsibrhA39YBGs1HLgvDiv28N3nN6yKLJU97Sj5", - "BLfpk2WoF8RnerCqjxHe7qFJjpEE427riMkf2fS6vUB6", - "BLWxzv9mGX3DLam8z59A55qDpF9KyMEt8krFf88Sacm8", - "BLZtwHMTMgnZJdhJQxQaksgJgteXFFDBrA13ywWagji4", - "BmCFZq2tQ3zj3qY1pjK8iegUp2TAHj6cYPM2vJkSA84d", - "BmytjrTNhPLdJg1TUmtt6JtapA66vWgEm2CQFsG6Q7M5", - "BmztoE61fB71cg7uV33DWBDvEP5JLNWJbJxvPDfJ3eNN", - "BMZY98zbjg2ey4XNfhBQXhEuvVqzaJ1T3AKD2quL3wnK", - "BN1dPUuuyfujPUcNaRJPquHTuqnxGfY2oeJUV28wTWMR", - "Bo9T1z62GVKmnttMz4HxPPtRXs2BUkAd7T7yUsKyG4iA", - "Bodj2iMEYUdwu1rt5EugntmwdqBsuR7j4XxBJR7TVffE", - "BPL97jdKyszDH2xxWzgS3QVVwuYqHaWvhsPxNJPg6Nn3", - "Bpq5BM15n4ps9zftpAiJARqVmAfUsmjSKfMQN7yEZARe", - "BpsPu22aaozdVrZu8kcqs7rrURKPH3fBAPnMF3oLG2Ea", - "BQ7mx4ScgjetA378LnL1Nm3xiM9bbLuEsX7UKxPseRCU", - "BqGCBrgYpLv62ebUp7DKfnjvSJ2qBc783kehzKJDERbv", - "BQmxWxDnbLEQ3Pr9upNnaeiMV88K77JiXVUNoSHtYjPB", - "Brjpw4BpNaAw8jvaXmVEBpGYzKfAQi4HdtshD1a1KDLt", - "BrmBMYWThXPvWmRKt89FsZScadEGt7fy1FRV2QUArpwL", - "BSF2yD9mqzaixDaLEraF1en82EWaXx7wbaCqSuKppqG5", - "BT5bANJXEmnacdBHiVWCMGWckJEUBU7VRiVMiLmA65JN", - "bT7ZZEREYCpTB1LxvGyBLyjviviZNVfejSfa4R68GmE", - "BtHbnzt6SDwyKpzQFUS4ReNEGrL7YYwhuRoMdV1zM1gZ", - "BtNTPnJo2YWQhiaSQtNnCeTz7XDWUARRLSshe1smVmx5", - "BTPUdVrsgfKFPyBmy5ozHvzMk1QCK9vii79wgxtGhjgn", - "BTVmKrqHyQU5vSqExPNYeozop6JPMCgCCZkVfCMKEa6w", - "BuFKun14y2uagDQXKou6x4ArWuG46US7X8TEEJVvSMTq", - "BunxTHgkSEyHHMikCe9ofDB5dsgcXKN6nqKC5WQsd1op", - "BV8sS1jn1AvGAptY5TxNZdcm7aa49MZCXSpXQjzjdnYG", - "BVEX3B7fRUbadEcigqknwc3cM2CUXpyz9vtTccBpwt7r", - "BvJSLTtfFz2Qt1MLDJqfEtMw8uGtiB99nthg2aWGXBPP", - "BVLVnUm2tkgX1sK2f5oVtTMR1opGra72s4qBD9LjMd9Q", - "BVSbFiadwxwi7RajrGgx4KAuwY7f3s6sB5AaL9pGZ4Hh", - "BvVKJxCQNsFWpB5o1B6To4uZzqAUgNXLcfbS2inyL5XU", - "BWBZDvXHUsm5WUhDBzA65TqMF2CNSCtow2M7tfAtJA2C", - "BWiftESMUsve87rkjU7HsaA7fkiJRAbv3xZLQrmKZtnz", - "BxFCg1xrZukbRHhthKXRY1gZVnHvu1xntdg1YmYnqeE7", - "BXjzAqxtjEnUCczhNzoK4hYuiH8o7oB7keMPaSJXKpD8", - "BxLUkNxbwARzCsroVyFSniLBx9FirpQJviXUiB1ZpBXQ", - "BXWqrL3ZuDU3fJ2qbBGmmMagLBLgWv65YbXxqEat3Ud6", - "By8BBocWV2yLsEMfkfHk7JkCmg3wjh8hPyKF4kd5nTrZ", - "BYxEvmSwA1o3vJGhooJoReSjrzou8A9h1TZX9S4xomHP", - "BZCeZyvroBrSq2SbwjQKU41kcxkutUti1A7rzZqCfaHK", - "BZehsFmSj4iUhwxHNqJVzduQQiaLqhzfE5mNT92UZf55", - "BzwAtaU5sqkd2wALkiR7A7TimJzN2Df6vr81tMWmiRky", - "C1QUyFjgVeG2mNBHErtmCLz8BUqS38saMUz8KA8r7921", - "C3hD8Q7dLoodUm6E6LTWR3XqJgcRrvrVaMscwMBV6vaV", - "C4eTa4tqvvzpTsp9pa5NKAbeDXJs6sHWS5BfxGB44Xex", - "C4N1bMSzbfDwHGMitxyufNZPaAkNYx8vJxHRnHWrptAT", - "C5HvMeXdHGxi7nVTFPF6KcyK77RSWLLvEEB3ParXoK1F", - "C8VJytJbZM7KFMXHNUdoF4V7V2QbhkxNs1qYybRoqUEK", - "C8x8gRPxVQd1rk9VG7fm5MqtbPkTF7C9R7NUvb8HJ6xo", - "C9UahsjNtQao74K3zYdJdkGrhfcn7Rf1szmMtUP6fSRf", - "Ca8DQQagVHeUAhWPWxGCmaMuccr6aGsm9HxeedxUKBC7", - "CaCaErMi1TtrTLLv9jaM9VVG95Tva2keMe8BZSuji3D8", - "CahiUdyge1w7Z4GrsXNpVYamxj7pJoY7uSThHC1LCBPE", - "CamZtw5WThJCqyBYuoBVN2yLBg2CjCin6SD9DBmcQWDv", - "CaT9dSx37Quj1kcAXEVd6ncM6NLvYUSqhtgEnn1JtNKC", - "CbhvvtosVdVwZ8GVrBqgYT3JrXLh8JRqgKpimhnZw31h", - "CCM98AN1SENGvAF6mNvYsCvQ8SPbommtAdxSLdYwdt39", - "CcorN3BoG1XMZehZ9Xib9YLo4mcvo7pzeVurC28gYYqX", - "Ccq6zHdtv3DWCP4AccTi4Ya2xPGsEVHSfoPmQ1qffb8H", - "CcZTCsb1HhptTfLCv8PXLApzVzhfvXi1MYUnmyiWMsY7", - "CdgoKJdFPyqLXNmTFjiXSyrUefmUnjhdQr2kpTvDBfe9", - "cDK4eZakyrZPT4fdhpPUt8q4EekNEwwGEz84LFnQb2S", - "CEMuwgTq1TXoTvdFjuMYfTu8Rnvo8HVUbKGquAsiLCXs", - "CfhJ45Zx4Jod7LydzyrDyrywhmreZMWMZaT4p8YtdaWk", - "CFtGf5wQ7jPgJVSk4GiVxvqVZXfkpxzdnkFJGduUKA88", - "CG7zvuaN3PTuQN9tFNoE5jERxtYwg8YVuKE5CMYD2jp1", - "CGgiEmA5whBdjKKyJVgFEBe2Z2qDVQQd2rMvAaUJP6Yt", - "CgieNgKQw629VPiovu6iHbtSQiCUt7jKBWnK586LHqTa", - "ChLMXZ4KXsMpa8W1VymMxim1vdPSK5a1jDwfMbm7cycT", - "ChorusM5BVgnAKbg9PF15285LkqeCoZWK2p9s35T7J2A", - "CHpj822jTX22VcSqzksxkJLB8kBf5gDMCqYbgXv36dvN", - "CiY5RjWPs1XyegKyBLcG7Ue7YMf98eiEnmvqnSuSKbob", - "CjhKCjNC1WUgBjAGst3D2XmSsWHvt3zGasasmogPTY6J", - "Ck3SxoXUShtXfLKfUUXAtCwrFVsEohESJfWGWuSgtTQU", - "CK9yiW9cCVkJGs9qB2SZnXUJ9Q5btmrGWp6KuomttDXo", - "CKm2wXrhngjLRULcxx78k89VnpGvpAiRJ3DJaF9tZQTz", - "CKs5FjmJ8qx2o5gzCJukb9Q6Z4TEJ7ogJjuA1Fch4bwA", - "CKYDvsLjwp6tPXfYxLmBv9LtX3FPpaAPj8kw1Gqy7s8Y", - "CM1c6z3pRNgHFcfZG4z3wE31jaR8c4gCYQBJVEoCUyq8", - "CMFZtuwCGnXbnARnNx9JrrAXhGHjbGEis9ajFwYPGqCs", - "Cmg9ZbuT5pR8o3CBLo4iwHCMxWzd21ZyNAoLH1sAwHxh", - "Cn23bN3TiQGAFiByaJxp8aE7suXJaarQsB321wJqEAJM", - "Cn5H2oxjXemT13eeFU45gobRYiJrjCrhGaqKTMd66SZM", - "CNVw7suEhz3LJFDzN1sjin1MScbjRPWB9yZ3tNT5QrB6", - "Cnw2PuZHpJjpLd1ZxxPxetuLiXHniZjjYMGhQpJYqRBU", - "Co7UqfqzXzTjhBwvam3zhNi4p8dKtdSrfh6rQykoNMy7", - "CoCKdrHVE1bjMZDwP8Z16vd7U3E5tGyt1hLw4tTsysmU", - "CPi7yFjqm8MiLFJpdyfWowAgQex4DjJxxHcLa2rYZ2XZ", - "Cpp6qidLhCztkpTroSD8jwF3ZToYYmvLX2PdTs91bgqN", - "CPPVEbGFbX3XAThetvfveCE1vYLWUwwJGT7DxkPAWb8D", - "CRCp8aHuYiUVfWMn8dG7z1T7SMi448ruuP9n1e6NEMmt", - "CS1Q8yNkw6a8SmY4nJ1jKrqhaDo18Wr4CnNbwsvKoswC", - "CsaAGRau3ZvyMQvJ9CWSqbqeVv9zw2Am8FhnL9sr6jTk", - "CsiPaAm9Zr9EpGojSNjQ92h1kcKQvYubiKmpWb3C8B5w", - "Csrv9JCbebTKu1uBWqkfwuPHwVCXsYDrQmeXf19onbsY", - "CtxU5HwVbgspJVtWxwjuP8wXUMdkjYJ4EJwJ3jvZh4zu", - "CUdHsUm5eaCZRctJo4HayvvYeh3AE3wCrNYXvMtVniBc", - "Cui1rpu4rp2f53vzjzGGo55DHvgf5HQVGqNbyRwjWMXc", - "CV3F19YAhoW7DpfHQ5W9t2Zomb9h21NRi8k6hCA36Sk6", - "CVtdVkbhutoU29LZKuDM12EUZmmdVZABmPk2CYnjq7yn", - "CvwM8CJEGbZhC3dVnVtmBAmzirSjAvQJ78yEvsqWJkPh", - "CWL6skWfKLDd6SY7NnkjfMgNR1QxHhxCadyFNL1ssNaS", - "CWm26qFBekyTtUYg6ZLfJi2ePMLCdXjGkZkhFkXqJfrn", - "CXvTFeiDYsmHfUXyYgm5byEwM4T9T1Pcu5qRiTfKdsho", - "CYx1c425b2sZoEmFxLn92cb3QFvTY5umgmuwBiiFZDZr", - "CZWpCTN4rCWer8fm5ZqFdx82CDiCJjZLKZ5Ti2gdmchQ", - "CZY1ZJAUyD2ZfHE5ENChUmhqSVFwPnTm6Aq6N5tbBqaP", - "D17iHRzwBk5NFzAEiUb5JqhaqDUM269utRqduzMxcTT7", - "D1oFvnJJFoZAxUPDMUw7dsBgy5c7A1at8PEGiT6XEthk", - "D22jrsNWZG6qzTURrT5PM6QvUBt4vHLYE7dx4Frt5wNu", - "D23NCAVxinE53BTemguZCheAqCdMGfNTUzWdoWvq4Xj", - "D2NjDkcv8Y1dWGdtWAKPT4em2D3sYzM8AzMTpCG1RVf7", - "D2PNC1USZ1XZ7mZPgdLjAvbDnaWBx59WKKM3CxjAqyu9", - "D4kv7YbigKSHMbCpzLGyP8SywUAPw7Kvn5VdHkx2gNom", - "D4pLf3e7kDGC4yc156Mb9A7JSAYnFH63jjsvAkfguqZB", - "D4xPTEsWkU3zN5bDyTX9zgqnAhMoMccnCRGRLwSfo1We", - "D52Q6Ap8RVMw1EvJYTdEABP6M5SPg98aToMcqw7KVLD9", - "D5JqF3qkLkeJKKEi145oMseEGc1ym9cWKtBKtg4ZBBnN", - "D6beCFAZeFtXoZKio6JZV1GUmJ99Nz4XhtxMePFvuJWN", - "D6q1Ju9mSkJLokBE3q4ujrCf3TdLYLLRC95Tatf7TViC", - "D6svmbCCUDFYmw8burYWAJwBq3e3Cdp9wiLdfNZ4SLus", - "D71JRzjPpHipt8NAWnWb3yZoXezbkGXqSf7TVCir6wvT", - "D8goKEZAXaWCfVSFbGKZQtFn3B5XFdLLmJgUSgMjEJf7", - "D8P3w7GQ4zTYbJfEGgfdQWQ1vrL6umGYAUrMz4hBJjrN", - "D9rCbP5rBrJztzv2EaACNt2LhXVLpPmsNgcWyB6LdfWW", - "D9YkGDRwdQaPXZe6V6WwWUeTWwfSoNmXADf1GXePetpC", - "DA7SNDUGAHwcXxHoUhbPqTv2p8GnncMpRYYoT6eJKmSR", - "DaB3ZwVtGLzSjazk5STQEu3MkJR2nkK3tDdCPAvx9QpM", - "DadnDZbFH5BHHRHD7TaobaSQ7QATXgvWegHUcZ7ZGzmW", - "DahDt2bS4EWgf546qQm8PLiRZuZPGeUKD42urQJCBYJS", - "Db2V7nPHc4sPHne87nYXPGn8Kv8rMsiWCAjgAXmpqcpC", - "Db5FG9D5Z1WWDSvQioKkymwRiTTGcTHbryBniRqYE65G", - "DbzdjE8TFSN1Zb4g3N9NsgFrzJ68G5WKtgSxqVox7Nxr", - "DciwdVV1DXimdsgRGQuQ45zYVjZNaof6a6EZ1JjaCsvx", - "DctYdX8c3qBZ7RUtYE4Ffunjv5SYFxVde4H4BDejPzMG", - "dCVbRnKNv3q9aBDMyvLRBYuWWt6tpEWjpucnZuJ2rAd", - "DD89H8QdPyWGtR5QnrfM734G4qrD775HFGMobyrkHjn9", - "DEqpqWRASZVoDVMQc6NpNjJbiY5KxupgiUXWCsc4TUim", - "DeXED9nidMNJJa3ie4ZxC6XAw28aNhKmv25FDJjuqDX7", - "DEZAHY54DgLq9Md8CyxBgNCe5hxDQi7fJaSE8jymtazr", - "DF57amFm9aHKYL9pKLSWindiF8o2RRxtReLb6d8DQc38", - "DFb6qaAkd5DTnFVYLDjzJNfsUPygP8GHHebN1CBv25cf", - "DFpi7mgmChYV9whs4uEtioFG1R2WF4TpGd1zcXMjGwF3", - "DfTeDaxk4RufkVbykedVnqa1r9S3z3oKFYL3FFmPdr1o", - "Dg5E8ktH4GWfKL1vuVTdqZJEkAEgtV8LqmSXyLJuZ3q1", - "DGf8USMPMty56BWgwFSUz4orb9smQxsWxufKBXSoX97f", - "DgHhYjwQfSrtyKCHHZ1kV2DB2ce7pNPKQsqEWz1NRsFq", - "Dh1DRj5mLYMeJVGvaPZN7F4XjpX6u2dCDXVnUXrE8rwW", - "DHa2QSwSdf4uVtFUyGeTPJ7XZcKrStoqQhHDa6dugP6R", - "DhMuXF3UqZvi3GhdrAMVyEQ7pW4prM8DkW54scYXo9Ke", - "DHNSHtEZHwPkkfomi5oMmCQy52ACoDpD5Kc6oNGTJTth", - "DhukytoqRv1H9J7LZiv8FyqTYhBhqb53gMgJT3dtdyk7", - "DiM3w5M4ATTQQheYRrizFCSoKCKmefPGnah8cPsrYt17", - "DJo6wDUWAdAFvuRvy938ze4VkwCBrW2o28pbcZ1qZogo", - "DJRbum8r82ts9uuGg9W7AheFwRE7atSV1touZPn2bEcH", - "DJvMQcb3ZtXC49LsaMvAo4x1rzCxjNfBfZtvkUeR4mAx", - "DKNy6YAPt6zq5jVD5S8EFSXpQmqA4NjrQf8t5v3tHo7h", - "DKnZytVA5wKbNPYW1pvPpoE5YeSsxu12KJFa95gBAGm7", - "DKyon4vSD7mF6uqgEJujABpEdhRbyX9X9EzFjmEz4VBx", - "DLDshHnnGetLXCyk9o3RpKC4iRATqgw3UyftYF55ffuq", - "Dm8Kusyhxmz2NmwF8RivLKembinSL6h7tvh4vrMVNxoR", - "DnPv5bC7CZRUTrK5R2rJ3LyEDLcTGa194MxEoEBSutV6", - "DNtbLVUiYdwbKvcYvr9Wy19KLUvxSkhbZPAbqAmh4oDJ", - "DNw5GVXaC2ZD7zpBo4b85s3Y5KVwkmqDE61Sjbjutjmq", - "DPqppsgQs5wwx13ncWwmRkS5HotTJhgFHXtDj6qSAQbY", - "DPRGrY7hQxbG84ju4zC1MBgYivbydnjk3zn9JDEo9Pce", - "Dq5r3zG6XGBcXNDRSWPSc7DiWwjqcGoiVcEhZ9mXEAaV", - "DQAi5Bdgz5aPhMMUMo3Nun8TBewGf4zJo2EqGt1jNNQ", - "DqbeCr74dFGDPvg8BpV6V2Jy2BCTZWmuvChkZVvPC3wP", - "DqPvDQAjyZ557yaHJJzEekV11WKN5EZ6HQujNXQL3FJL", - "DQSg1PLT3Px71U4LsfBNhg5yT9GgH8FnK7qQAq1aLmk8", - "DQTiiFVnwD7bSSgkMmwUsBsgnNBza8N6oEGeMC8YaieW", - "Drf2oN83THfrUJHA9AGzJZaL9KMKggPoL9HJVttkSCgL", - "Drkj3wbHHmE2iCnqXHKFTmwPkuSc4bsFdgAmqv6eXuWi", - "Drskw4YqMzYRVikgsGPACY1GnE4zTWs4uqSKajKdkU4Z", - "DsaF77cCADh79q7HPfz5TrWPfEmD5Gw1c15zSm4eaFyt", - "DsnqNtwKA817a2VQypWEzaRXY2soq5Jgc68MgFBMR35p", - "DTDiBe1ZLTJGzazmd3k6oHxKGTitNT6swT68MguT8QaS", - "DTPPJWkD94MGE2oA3cyszmCAS3QvxNjXznnRGjpanbRS", - "DtqjPaZAuxaNRsX1u9e5EHFF2JjeTFwF5SZ9YFJ6PyTj", - "DV78gathrorcpWsWrUkWrWNowLXpizKsPBupStzeAJnL", - "DVnKs7XAL9au7cWrTT335gZ3agJVwrqeSVnSWANo1SJG", - "DwCuwTRTXQWm5M2b55h5oyx1zWkNvTUVGwmUGvBAVbqc", - "DWic5rF2jQeAQr771cCgzyLbEMgXaq1AUyhnpmgDze1a", - "Dx4bMuKpGaxAnd53QYDyKhD45PjuFLx16mrgoRK36STf", - "Dx4qoPTLSRdbd4h5cy2TD5rDyV1d7LxQYdSY1TLStjcp", - "DXCzguRGhTGvFm9hdVsDkFi4S3n6W2yrNeUjrFN8tkvL", - "DxLtXrLUrqja3EFjkR4PXNYCuyVtaQnozonCdf3iZk8X", - "DZPn1XMuoBpNQzcXozfMMCUJ8YxgKyJP1Su5oKvvJk6h", - "DzTb7aPtvxo5tbbKxEjiSuBe74tdgswdj3BY8LwstoBg", - "DzxNmWD99qvkPdDR94ojXhUrpzT8VdqB5ktYX7fZr4gc", - "E25BqJUzSjyzeZQR8LYUcUNNVrgRLHhXxhPtZGB7KCCp", - "E2cy4hqcUpdyMpx3TuHKpdW2cJZ3cTSthk4jfqJryt6B", - "E43Lu6um98dGLscCuPUobgKC2oLANeByzqdab5KjxV1W", - "E4YYWrsKv9YkBjLRtVNYn792RavzkXL6NPJ5Z4sHXiG5", - "E5yehypUe6uYm88hQWVTX1AcAZJiPgffV74GJNYHPxGt", - "E6MuSSCF5aoBstVcZaD6sk7hkQrxvh7s5ttVt8NzAiNM", - "E9bcuniYQhMscfMjE8zaAXQ47TH56gsQoKuzvqXHxnAY", - "E9qZxXtwWT5FuwsXHLjA4cjJyyeYb3ixHxBSrJJDzPwx", - "EaVhV1UzbiAh8BCdTiAbvoGWktfK7fdR4PEXkkN1qG2n", - "EBDnuJT5USg5HsQSZtWT1q8y5XjgW21b1ebYSahcX9V5", - "EBxhSfAWW2Cfouvj1k242W6U8krZVAxJS47SG8UKb4ch", - "EC1TjttBQaKU1dXuMbv4ZMSFXuPDt7UCMvNXruxCXdA8", - "EC8cRNmwgbhbs5LtvufLkme1QqedbugySgkofYtPoDKd", - "ED3Y3cuH3wtHXT8TmbDE5toHU6kwQzevWtvkP6rGFNgc", - "ED4pSxzaemm1KZ2kgSnimKp3nw8GB4qpUSmFCxhqUKRw", - "EDD6CuVDzPU7g9PCUZcM7Bf4rQqeNrt9ugCBh1iVRMaN", - "Edmn4FjZMGSmCjCE2FBLzHNjukEXbzEKiHptMfj87uU9", - "EdSaRxfyh1Wjeq331Cr7aSpdentiPyCPXVHvSacovueU", - "EdujCuWbg7QKyty42igLbYvxGfWNWB5VsKZyi1wHbHTc", - "EEBa8frib8zBLxj61NEMAUoEyrHFgV9MUzneHVHFax42", - "EeHdr93aBEXELpbDx9p8ScgzstUZuNZmFFHM7oPccXzS", - "Eem6rzePhp56kYBvWNgU89PNjrnWqJs22WcuiSjmkBc5", - "EEpAEPJ1MCfZJes2sdCtkFwdMWvRPmDNnynnG2JkhGso", - "Ef5gVy3PFRJA7uQ4UkAD6AufNcZNtHN45k5N3L5mYatU", - "EG8D25QxDJ6nbD3oBpu4tPDvihriy9mFiPq3CxCGFiPF", - "EGknxV4LZM4DNL1Y68iAPQEdLsMZbL82wQbDmsGw6w8", - "EGR5mW7QjJriWjPzDswcC5njXPx2zzTruTRZKS9X2Zbv", - "EhJnXqSV4wjCEA1bH8LeZQZmJnMQXJEMj6Qnya3u68gn", - "EhxLJWG4Mx4QB8MVfoNLApiD43yKRES1gdD3zQzsFiLp", - "EhZmFRvBcYQU5TscYdQV2i66pmmeKrzecbHYbUT9fuyk", - "EjcB41hrq5Ltr9Yvda3jQ8zGkkfFGKadkykTCQnPeCne", - "EJqVBubhCVSMFCXrLWPUL5HcA5dkfVMcJkLyPRzAoUcn", - "EKBBsq7snZXyabwMa7jbyyRTMhaUQqtDHtpVgDnSg19c", - "EkVaQMGB3cbyKdqBwBagGtURjtoXsP6pS7HGyizwhUs2", - "EL3RZmhvLAMMoDip59M3oKgqXXzHAPdZ88KQ2h82mCB8", - "ELERzoazbkXxQdP1qPGxnVVGBJy2W7Do2MMRt35N2H7J", - "ELsehFqpFHn2hJoJgEuSCpYhTvjCxFz9ToiiCXWUE2Tx", - "ELWMKHPVZpFTwBSzVPF2q4nmvexLxWycjy8fuoC6egBE", - "EMeaA1d3kmoBNtZQNgqEZS9y44gMrA7iSuqS4nZ4qxpB", - "Emqe9upNXhojTRVT24mMxLpNB3Fnaoa1FibRtVELunUL", - "EngVeJ8w7soeVvKwypuSutnXFPSWDLMq3Vw5wuAdSGjf", - "EnLMAih8NTU7ENb5tiTHqgP8MtTUnY4QDLUKrsRwhjtk", - "EnrrqXLwEwgDU9yfa7YVCxmm6uj9vjhCnNUk3qjpFgws", - "Eo1uPQgv6jHk5etCBX3hJ7Y1iYti7WqhisrtY3krEHCN", - "Eo8rLxC2apCYS1qQCzQA3CvSTFqbGxXEBe51i1i5sWkH", - "Eogtuw7vSstp33UQZ9mXQ4X8s1PSmUfJ9fQAxj6JZgWE", - "EoHfz2ybgn3GWN3TbTj2FB3AYAXCzhp4cWxMMnyAo4pi", - "EPdTTdBRGeiXp9yzpPK1RUQeinoCfgq9qdicBJqZcJgg", - "Eq1A6L2ZUpy1KPVni4TPYvedSTiFSNNTiJdECskb2Qrz", - "EqaMZqSjRtm1c2FKLmZoSp7bgzEW9WBYVfT19n74cYo7", - "EQFsB8CDcLsCYeRJxhZ4fJWnXjCnbxrbhyqjyUJvkDcL", - "ErbvzZx2Ss9GxizKyDviybhZPu8noHv4AM5vuzTh1ij6", - "ERWJKBdJPoXa3kq1gFJninu65fYDTAzNSPsDxCXjNX6Q", - "ErxAGCPBB5wMWU7mgZRXUoNyYSnMmVR9689hd6CMTfsS", - "EsLKC2zS5Su5sHvkABXe6u9RuCv7q86jGiwihSz9uSav", - "EsXshV7Yva6ZiY5P3u41vjWYNHTNMaS19qcoGAdiPZK4", - "EtemtT8ofMe1puaYitDPxyz7KHXPjsxNwsgBqYYBCr8F", - "ETMbiU7hEt7jkoA8H6ACsfeR7LyGA773k9HA13yJUfex", - "EtmHTosfXS5zbDbTd6RxWvGLWwmT6fbjR8YENZ6byfQ9", - "EtpFdJnQ25ZJMheLyURzyCD5ch1SL9smfMcEeKfAkEHq", - "EUoXy9YP2tAefgW5CHEvMGAu17McAvrXiQ5ucezjNYcd", - "EUwiTG1ii59qWfgsJwEMjqh34NmShMdP131BWWqJVPaG", - "EV7arpFrG8SFFAkfYRMEJtuqocMeXpNFD7zDt22qG23T", - "EVCxvddWCFgh9LF4EJKzQb7stsPpSBrvTFUYnE51pX6t", - "EVd8FFVB54svYdZdG6hH4F4hTbqre5mpQ7XyF5rKUmes", - "EvenXreut1ywzoMaY3iXtwbuV4xcY2yz763TSxngja6n", - "EVQxcfApDm4snuJU1XHLcDmwqiLsAwRQ6MatFKmSTWv8", - "EvVrzsxoj118sxxSTrcnc9u3fRdQfCc7d4gRzzX6TSqj", - "EvyvbrFLX1M5yVRGFNHt6o3v3dBLgrz5NoE18rcwyyXh", - "EW8YLbq9b6saEKn6K9R1K29CSST1XDTPpJLeXThpkXes", - "EWg9NTC5s7Pa9FktUk6dX8xRYkvJ952peH1z1iznd4nV", - "EWQoNfVscjLbdHFAzCrbCt3FcQGuGFe7XWogU3KQ61Q4", - "EXaDpiWsCGQY9d6AUa54XBAs7fvxF1z7V63xN9ikMMvP", - "EXEFh9rPB1VN5NGDQsJiAgR5qaxUzHQDRJqAZdqEYGV6", - "EYbvBPU9mSPTVJrZgioTt8PGPL9Bjv5342ENBMR5X8r8", - "EyNimNczDewG7Ubov7T2RGKD2R7i54vbeDUnivnR6ePA", - "F12Ah86ymdNPuXya5i3PKG7jeLfSMGpoRTriVTgcXr15", - "F16J8jYx76jpt2vgTT5SPv8hJGGcrShzCHG9LBV5vQD3", - "F1TuusSghAobmbGAgNrdxRS9nBjwT6J1yyALUvpEA1is", - "F3bXikq6WnjMQjKcvj7U2tasv9Q21xTWVUTp48GmhVas", - "F3gsehGvHNXtF8mDbGVfB27Lq1paSgTiqe5nzvbFVREK", - "F4R2g7TnRmr88GY9DjhFo5Ssk9Ji3phBRssrZL5rQxWs", - "F5f3vcPpfwgouhVVzSW41XZRzch16jr2qx7pYNYyVruW", - "F67LCN4eLwqBGbHyT14nJw61x4d4CMtzdcvFq3tZYwki", - "F6ZzyJaFh2XNdDiZSnBHhQpqWH1YMifBxZNJ8JXeFwXB", - "F7FgS6rrWckgC5X4cP5WtRRp3U1u12nnuTRXbWYaKn1u", - "F7zQemwQJo3bKVAvpcCAfkgXD18kZxYvgMxCP3X3qiK7", - "F8ZZW4WKUx273i4L2KubqUCVSKLmSgkpxwHRL7gar1F6", - "FA7DtFHm4gh7gwtwdRphSq7wFdWBU4inVnrchCmTKLTG", - "Fb5cEcYNgPXKJoEmvPvsU2ENYRVePQtExqgf77AnVX54", - "FbWq9mwUQRNVCAUdcECF5yhdwABmcnsZ6a6zpixeKuQE", - "Fc6NB99bkJQn7JsVSqdJs5fJEzj7KFpe4JHNQCGVCctj", - "FcTYrxp31zVjTW4qjFKkgRcKXbWcBbiRQqJYpufwcJZN", - "FcWgrc99RAix3y9th526GnzN23MQSkFmyWaeo9xJ6Jfo", - "FDAR4Ms1QU9vparYAwi1jwYuvy8Zn5J79XyQvXWbHLQL", - "FdC2FZ4geXeEh4pTPXWrNH4nqsriB3xD3GME9HPD8CVR", - "FdQgwQ38ETKv7x1mWNoAdrLR2YZyp16xFDC9YR8Gseva", - "FEKzY1TLRYWDc7AHTkREpoSHvx9EyNpPmxp9FeojPbJq", - "FEq9FL3hzRDMtL8DinPAaeJpb28GBZYTpTeRcRyHSrGA", - "FFhtic9yPS8ao7Qg1GKjqyzwhGYK5tsksT9VrLioTgbY", - "FFRanhUkAFoYNPE527F7BKeaHe44Pwi2SaiaCoppkJCz", - "FfREhUvTUisAFG9mHeetnDA9zYEGady5BJqj5jyCB5UY", - "FFrx4NAJginBWNm155TXLgx1annkmdqEwAP79nNRwxjQ", - "FfwtopRBJWKEJiCmkNUFyaQ2FMubtzMhAzKgHDF7XrLa", - "FHyqLxzvim55sLcM6SY4q99jqe5ifNi8oaj71pAef5gw", - "FiqLajUHAPrdmSZzcuy8gKNU1AweQpCXy8sznWgGEZ4S", - "fish2tcDFRiAM1cNKqF7b96WzQmmDRjsf5XD214MhpV", - "FivGzpupCvU4yr9E3J8RvWtLNWTm6ZRcGS87a51BVHWS", - "Fj1XTsZGwbr6H72xaj4fPg8M4QyXUdnKJJbpZXunFpWr", - "Fjc7dkd5ir2heioaU8eomUgbX2JY49BCqBX3doB8o3H3", - "FJKaQebiX7qd4fy4dhkXx5Re88B9DVxLT1pQRiMuUTrG", - "Fk1pCDCzbBULB6Kw4cQUdTjvvbLBooW2TPSZjvK6YKA4", - "FK1TQPnYVzg1e925kHurusgkXxxFuBfEko6D8ZirKNeR", - "FkeDv7mGz5na2cycc3fwCtxmoWvZ8WvgVNxjYxeFmdGH", - "FkMj2LPSWd9LzLZrpZ2L9YL1CpB5eA5W3J1vyvvpp6Jm", - "FKny5Zv2nrLFKfNH4jatujiiNG2c5mq7MXweKAEBBzse", - "FkYhpz7HSGQJvA6apj1BKoUfytQvWseLfSUrE3zjvkQb", - "FKYKRLCFmh7uUASUQjkL91yXCUuJ9wdbPCZEnv8HkKnf", - "FL2Fo4xmVeo6dGgsaBgJdG6sB3Gk8EmEpMBe67CKopRH", - "FLcUYvDMd5nh4cyP3oErMHoKnKREmza5rdAZ6XHYU1bd", - "FLdAnmYGeGmwJY3qECfcZ8pyQ1LoTAeBPm8YKFDxQrMN", - "FLHB8AGEsED5jAF5sS1kSkAzSXVK23iuT7YDPHGmbcjb", - "FLjMwfY9ahmyc6VgQpokBrra5Ucf5KSK5YW5x9MMKnpS", - "FLpMRfbSMkBnFXDdGKdzcGP8JgrNVhaYowmtArNughqt", - "FmaWRHAtnhTX3iDhgTzaFHpcuP8TgjWux68zo3kJxttT", - "FMHjnmeRLszDSDTmHrbqUi7rpXLcrynh9K6jQvjdhqf6", - "FMs94yuSx6idmVsanrH6KrLdtz1CyambgH1jxCLorxHR", - "FmVd4YWnsiau4JLHYxpRW63uutA2sPKpKYGiwB3hBkwt", - "FnaAWEDBPSNCUk49EM6JFS2hr9kGqXKkEDXkw5fdR887", - "FNBpvn9cNMmMA8GRfGxaD5P5zkG8m3YAJybgJkVi9bbK", - "FNdoUuKVBigMFGpVvSMLXJB4FC7XQL1RjPUqUiwvPiCS", - "FNH1XmR5WgK7CH7W7YdcfxtdgaKFueKtqaggVr3CnY7M", - "FoDccJmq4PksAoMpRbygVVocdp4NrC8PSwwDd8nfKYzv", - "Fou7Du6KtVb8dVMzKMYW39fuSGpMzJGwpkQ45NbxA3Tx", - "FpcTktAA3ZVCNUfgbvFa777BwdChhX2t8oEoueeJtbgT", - "FQa4mYpWL7mNEXe8dWbd2FXxpreFtYJkD2S6hMD1oXHH", - "FqdAcsUQBMibVJVr259uSAnA5FMK2xACaz9vPEtdvkYn", - "FQFrdHAhKFP9R5R6JkJPtVJhLDivDia4cNNUcL6Eja6j", - "FqheXr2yJSTRGncTqVFFG5sLaTtXZeQbkQAxbL8mcGru", - "FQPRF1x5eFUdNWvfVwwJkJdqqfstGnCkEFVKEKHp3GVG", - "FR2rptYjvSsYeDur8khPK33q6Byjn4if6Fb4oTiJF3Fh", - "Fr3WfD9xCLX83AaktYvcihvqoaJKh7f1AnD8mCN1egHw", - "fRiGutrC4h4ZdYVE65g3pCeJNDg2g9j21AvMjhDMwW8", - "Ft5fbkqNa76vnsjYNwjDZUXoTWpP7VYm3mtsaQckQADN", - "FTUh2jo7GmxFqLy8c9R9jTPapfGjwcaDdozBjhKJz7UN", - "Fue9LZxjhk2DNXWxM3rPKr3z2qntChdeth615m7zUo8v", - "Fv4zJ7RvV8gEYxEtLjnGZAX1qxjqRh56DzBgqvFEVjjM", - "FVnG988wW3uF613QVxmQrkwtdzS8taxjFsuARTzZBwMo", - "FWUFG4jKyCVpEhzYHAYuRNjjFpfrt4y9NifzrZPZfwK8", - "Fx7dVi2oVpynBKzU2V7nRDbdfBjWrqqjLFxULXCVp2TB", - "FxMwrcSTgb8RKFwJxa6DSbsKQNmiDqstRTUeKej4Zw8D", - "Fxv1ymSwB6tdRCbjBURQK6P68XR2njCGfWbnfzVciJsP", - "FXVTpozaNNzwiaEu5HbS9EK7HMNm7QPLk1UEH55hAkK5", - "Fxw5NgncJhGbnjH1wuZuavVPDQcowTwG4wKiWAB4WNAw", - "Fycm3maimWfFWgdLJubtEogL1v4aJEkQapRwWRPxvf5m", - "FYH7U2HPhgxQCsHBGDaC135Rsx4tZx7P6ZjxnGqWHBHn", - "FzAv1TFpCyR65GrxeqBwnEzNVXEeUMPV5rKZGQhPR7mq", - "fzCFpDGUcyX78KEMSfJwczi61td55v133eyTeQtBuW1", - "G1uCu6JrV683QK3kdAzEiiAEBSMk32Ugy56u685cynJ2", - "G29KDaE6ed3YWzWaNesjgoBu5CFJrcHe9sb8dr7b7LLq", - "G47WACh32JUcxyiCna7UYw45tyYSFKQ58yFpUmhmMybm", - "G5r4XSC5D4Rw4NaWjbgBKnj6bNDsSGUvE46w9BYAT79r", - "G7cSi3avELxMLTCossnsooLj6UNhnfER6kpnSx8NKHfM", - "G7gAgJpRHnRvFhrUMA5khWMqHJ3tpWVWdpsBvCq6w6MY", - "G7mFk3fX4xQmBV5je4926SzLCphWFoww8APYxQKfkNxn", - "G7NoACjYzRcrLibw3dbNoDCVoBR67ijm3tYeL5zL5qKY", - "G9AHwpSz6gRb2PYQTj13oouRmpN1VAdHwXGzb1eoTfCT", - "GaAb7uwik3bGsMurHJNmbabF8G8k2cYJy4Wrv3tefuWc", - "GAPNvBD6MXboQmxP9XTCC4CMsT5gUpdFZWbnj4Tz2s7i", - "GaTDMHvngmoJhuRYrLGcE2GMCofu7K8SLGwkCkDE1mYh", - "Gb9j79QFprtbY4sieaLZGjQr4a5ifFxGdnU2qkjPbBJQ", - "Gbqh5eq7nVajFNocG1GZGikoiAqPstfQjHxdGBc3SD4M", - "GBtNh6c3Jbf7xMSA4VCAbjkJpBVJkB1QsZLh7iD6Hpq7", - "GbtVg3D6bNFSjem21vrJBJTpUniwwEtmvs8mQkX5XS1V", - "Gbwg3HCbD9gzma2o6oTqYkDQnojeZ1z7Ygc95DPFA2me", - "GC41PE9hngtmwzCbTuZQvCLN7C6xSLTC1AxRSAZSPRRf", - "GcCuD1yJFSeDdbogBFrnKRfPcv84wNjzN2MAz5vrv25S", - "GcibmF4zgb6Vr4bpZZYHGDPZNWiLnBDUHdpJZTsTDvwe", - "GCPW2jinG8pk2KfALJA2FYNhLKwCR42Y8ccQPXz2PYg", - "GDoZFWJNuiQdP3DMupgBeGr6mQJYCcWuUvcrnr7xhSqj", - "Ge2SFnQj7BeJsVaNqSrMz3XFGBjoFMMZ8qThYZRYYNr3", - "GEBvuMyPAM3Hmsr4UnGMqeeJNPiC6ZqPkCGKW6pADd8h", - "GEeL5VToy7H2oEFyLW5q4T1HeCDa6AA5YN8r4PiCnyW4", - "GevceSyTLxHv55phyp2PirpdsdqNFZRZSYViRCrXmneh", - "GFFuGhyHAr2fjH1DL42m9EWpAWXXdZ7R6PyzuMzDodLy", - "Gft346NFxfieeCXCHuwdQ9TN6HyPLr5oyfwGS4DGQWGt", - "GFZ3w5CU4Byjjo6BrQxVsiq9mumADrR58vH2TT2KxmFC", - "GgfiMJLWSKHr9JPR122BiyEXgCDDmFQuzzkKMNbNkykk", - "GgmneSMKWnEcavporN1vPpyTun2QRBzCjFCecQT5km8y", - "GGQDNAb7hFMu9XnXPMw7NvyS6MA9BfeAmaZX8yp1QXFU", - "GGQFKUi8FWGSAnNWeoZdpwERRgaW4VMiBdiZbEETq5Qz", - "GgsyCG7aGFzXA2A2gc2VCH5qpDB6Fz7zS4isJ4rfkrx3", - "GhBd6sozvfR9F2YrKTFwEMqTqhfUjxNUYKxye7ZvTr5Q", - "GikkfYtVZgaUtcmreVpQ1Eamw7mrnf2jnDFGJBnhVQhG", - "GJbU1XAJAky6sPVH9BGux11AGyFtkqZwtiRVS1itqcao", - "GJRLu6i8j4CJukLEQQXe3y3pdk3ynVkt7R7ttcfCZBoA", - "GKEcqfeBS6rP3NUZBV8PWrmmBkPUNRpsV1CqqyqBUkAj", - "GkuEkzsEKyhgmomjiS9ZxruL9oc8tTWYQHaUv6Xa4Ch3", - "GLKsDBjWBaXHkyMihjpU5ZdKyKWtUpJyE4W7PjEFSEHh", - "GLPe2gV9zG9kwJmNj9GFBrzEiqridEd5KYgeSiPrubGz", - "GMEMvNsUerrfShmMJMqZJGBs2MkUjimjD9RxJiXzkuiy", - "Gmw9GarCUcQNYnqePXNBREuLhcMUwXhQWZMAvxSUf6c2", - "GNDHwncRV2VpzXQLpGLvQUGkkfDFhA3g36Jg8ZthCNLm", - "Gp96C7xbTVp9SU4YDK26zYjnzLHSuHkfcHpzXQXNNvNq", - "GpowxwT8wY9x2uFLWhZtL3ELFdAMnpBxTrpqFgnEukVn", - "GQCgtjErUk8HCgayXyjuCFR15pnssi4saPnxD2Pm9oav", - "GqFWgFDHj6fgahisFk8TEngmsEdkSxbmk8ZktpgW5LaS", - "GQnaJJu7h53SVVhVpg2ErkSKhYMtqYrqv1qr13MUobuq", - "GqsnwvnnwfvevfovAfRu8XrJwGietC8h8t4dwyQerbfq", - "GraWXC11stqBmL86aJW8cBEncRhAFX86mX4E5pE2eKg1", - "GRJExQVWj3Hi5RoMVb5LKNfCGvocrdyXi3QY8aGQ49wN", - "GRJohz4qkCV6YNjcSb3mRBYbtcTcN7GLG2cm6ffZqmW3", - "GRZ6gQmgkfYns4kqN2Unz5azpuuT6bwmanDmveRgoSgt", - "GrZcGUJ7baE8r9KSmrNJAKtgYAMiD7p2YfxefkbgTng9", - "GtU7wyz6vwTo7d82qNpFM6zsxWUnN7caxNMaxLwbwCEr", - "GufPaZ7pGsoqfkx4d2uUCU2E5HFeTMgx4k37YRZTn3Xn", - "GuKn8nEJwUPjBfxpwyq2MXU2JNrSpj7gqnKptCZeEk7j", - "GUq7RT6MzPK5vswngQpJdJkvtUDWU9cLarM5Rec8VW8C", - "GurfodDZfiVyd889TL1g2kT3QtafH3j7QbThi52Jjvvc", - "GUYiwgZBbpoJTRYkqH5L6zL1DgHH1hDx9c7zYi78cS84", - "Gv4WPocqzi59G7sbGiVWZAtLwDohpB8xSMG4kg41g3U5", - "GvB8xRCx7HFxuM675n41mSsC5adFre4Sn7CMq1V6v2MN", - "GvpfXu3ZecJRJWR6Gm2dND3DXe8CJvCtT8XHZXMsZ5Ap", - "GvRQCdtZZd7jVzwuestmUoj349jFVxL1Ja4GuxDYKB3p", - "GVS1B7hSXnUQMQWN78BWjT9Kr1h3k5UW5UTdFsDhtRGk", - "GvWoMZaf8ZbTnKKxrTGV5aGAjofinufohuqT827waAEy", - "GvZQ6JUcGiw26huYVv2eDTgrgVh3rKtADPYLfBiznVda", - "Gx6SwGTbYAFrUeBRMgMrgLUKaeGNeCKzkULXdEpwPSwc", - "GXfJaLrWgQbiuutiLyN7ijRgBvAvunJy7bYzaV562VWP", - "GXRPoAxz1gmqyNz3M21cKSJB47yAc3sJLGvenworEJn7", - "GZeAno1q7JYL493V8aED6XQzqNPjJRZMq84jtKdLhWNB", - "H1uSjkzRp86vK2xvC9tiYAhwbPShHUX8qPbj6RiVYWS8", - "H2aCsvmJvG3tQZ58S4dTXBwmqia2GHvctgd5t2p1u2cV", - "H4Dgb3KyCuYWKT8yKtp8qbY49cvaqZcisa2GDnroFsv6", - "H4f9d4Ru1BV2CVDyYsTRShVWk1q99DjY62LxccREKZch", - "H5aQjanQGz5Rrh4s6g4TNHTAXDzdr4czBtEJPdeDJ1jo", - "H5FVid8iRWjQAo8Cbvc7CJJGMwtTSQgk25sknxnEKkYs", - "H5YdwNcDt6DNeAL816CP3Kn3fYXFoigMw3zaASvZc4rA", - "H6djbzHAiv46Wxy3iwqD7LA8ART8YbgrWyxQPCNhnLPE", - "H8ACGbhYk4UA2F2nALk4aSia6Z8Vfnk3U3SnNDdENMAh", - "H8kdiUSyvHbxshcFmRqWTB1HZkQHKcQcagQ56TzLe8ib", - "H8MUh74GVNbSqGrYkZviws6xCmdVS3VZF1rbhE3gSESQ", - "Has5UpRZwnb7TrhyFPDETgnGThLPe38BiMcqkvXBLsra", - "Hbw4rccbiqiQv46RaPUTpUyAkTsRKFhTsbDuSUBQVknT", - "Hd9NtFQuC7nw5v6dbijtCkgAJj7bjM3vaqqWLsMt6oAE", - "HDitfpmCcy8WyJgNCQTrnZ8r71Nn7t7SjmVHnRwumGZi", - "HE35aDYTJHJ6KA7kLEXvENiRBX8c5UG5xHzgeKiXyQno", - "HEbMY624UhDGm1Qhy6neKSyi3bQjQ2RidSTyt7ARK8RW", - "HeeEbBAkuLzqxsFLcbKUfWmeNizywy2uzAfvRg63LFT2", - "HEgDHQD4cZsVu3QEjLLE49EQmuDoojxiZZbPywgdX9dE", - "HELPwwfg5W9LmXv3axe43EY1YGJjfVf3CcVjA8BZM82P", - "HEVxZQExGLJbpySA7MVumiTv6qbeCzmAQJT42CthZwoX", - "HfxzFiP19ymtxHagP4Zpga2zVo6ZgivpK6VkBKDowHRr", - "HG2CuUSFhdkdcv31qeyR13aS6chRgCFdqZfoFfPmYn2a", - "HgF66KCFTqcs55WAK9co7o9f4ZuPuXmFQTCKvRWz9A3H", - "HGHMEEHCfbVFjqB69Hu9oNW6SviukB8jUheEhYVZJKe2", - "HGkZ4BCw3mHYoo74ZwwzKJsSjnH8u5BW2poHVVMLTjuR", - "HgmPwzNcY85HfrN3bYiqaypb6Nmf7ayaZEaivGY37913", - "Hgp3kh6Vv8iw5wHD86LqkW3H3JApJeW3F5XLaGXkZZW9", - "HGthEYmVZTvoGptPHvgD1dPxxKMGXYSrPDcFAPSgdYYK", - "HgTXVg3dA51mGNSh9iPoeC6QLsy2cMEB8WPESRAQMBz7", - "HhjxbH3vLpUNShQB34NuMCL1Qc3xoiNDbvALWrAMCCnb", - "HhVZQersDuNPpxQwhVpuXiWiahZ76QybhesPbGjbmEnf", - "HiJ1pjUGoJ2G1fbrkYSNwPRrJ5ap3Q5usZMQB3pK7Zgs", - "HiVDGAGPSxxydKTY6BkjuLE3CyabGKyEuMMHc1yMw5Qq", - "HJ1hBuwYztBeiPhscJqQ1KKfLuhCcEKcPJQzKuZg14iw", - "HJhcE1XDYTRoHaDWcfkmfGvJuDWPZLEK8YkuMw9FYpP3", - "Hjqfrrmd8s8FZzucmkFh3RGQEN7NjyzUBFAX5atwcF9h", - "HjT9tCUEFWrUXFR37ahB383QTF4u53KWx9J29EWRfzdi", - "Hkj4Y4QxFvyoCd2wzAswsDpwW4vD1vyC5vppVyDDhJ8F", - "HKM7CfuNPKeU9crk7SWJCFgvFKvGh3VFgqT1sQVyeDDm", - "HkSTpiQR4YTP29yRBSactwZCKh3fp7NoLHLQrMK58xRE", - "HKu753Hd2F1nWLPvcNZHX6RAGSXkg6AtywiVvRqDXxcP", - "HkXUfo7jkpymbV2LuekirjvJDzXEREB1c8hfy6cPxgLy", - "HM2hzFLTd5TAhejGFjaXAm8LLjdmnj7bqQrzpRTaawdo", - "HmD9baVLsNVxALt5mo3yzuH85ND625cTDuDnvVo3sf6R", - "HmEUD98iS9DFkt5dUjtrG3jDixVU53B3YPKPbGwSPrC5", - "HmSU5YJr4XK2SYdF6dxNXtF9PQRzbXXupUXCVEaJZX37", - "HNJTofxjz68XBQxPHoakD5rru3qnLBJRVoRKVTYxN4EL", - "Hnp981DgpWig4dBQASkdJG8r7KzrgNRvGVUo2Em4ZTAJ", - "HNX6Tba28Y4o4vfU33s5HkYefZcS8xNKY3R8zwxwor4z", - "HoMBSLMokd6BUVDT4iGw21Tnxvp2G49MApewzGJr4rfe", - "HPisnDx9nRswcNBkqr6q5FSQ4saPj23GfdCAzNQcy5TY", - "Hq5o5jjDysktyUQdUxFk3RqbXvjSDyzNn1XtXKexHUu2", - "Hq6Ctthk4tZ9tT62kWnpnBqJ17y6CLu6dQVaQDDjmtmC", - "hQBS6cu8RHkXcCzE6N8mQxhgrtbNy4kivoRjTMzF2cA", - "HqXHSTtrUUraYZ4xcPuze9pX8LbRaV4wQGQ92Y2L26vN", - "HQZpRZLSzgDdPc21U7nCxXpK2VjMh8U4PE5G3YE9H2Y4", - "HrzzQ2MHeLXoMFFdhSCvuAV4y47VVDjVtDZSAenAoFat", - "HsWUiXARLPhYitGMapLYyMdV7k27kW2xzy9Z6L77jKBC", - "HSyQVMDPWiukduwnR4vS2fpuHZYWvK8LSnaY3UtrJoKa", - "Hu7DW7BoXXuKbwaFJaAMEXpBv8pqBJPhfThMD96WHiJR", - "HuJHVhpsf9nF4vbTWjgqgcCf2h97eFf4DnhAe3txLERo", - "HUoud6qywaWj8kZwdHRTbEPkKmskHa6Md1KNvF1JQFYF", - "HUrBwQeq52MqCih9c3yuixfrMWgYh1zuBZC8XNyk8TaR", - "HUtFMtq115zhNf1ecuHHhqhP3fJupC8vt1wkWevHf1Xr", - "HVD6ZDBgzjqYKyDLNadSkzev3qwSUnYEs6k81JktNuom", - "HVK74e6bD6cwDrK28hijNxiHZkvyXCXS8bd41tH6QwTk", - "HwFvyMbGLkiTUaT66cfL1FnJ26c9VqtpqAg4UbWSXtdq", - "HWg4WYeJHENvTGZ1xyCpFUCJHk9b4nireN15tA8fHdJZ", - "HWKwGWgWpnt1HYo7kAbtpuNzi6PovGXz3oWW54GDEQWc", - "HWvSRgESdWKDccWN91iRVQLN4rRyuCbuAHVWtPR1cJ1C", - "HxBkCVtiYAymCCv4EYakNDSCPgog3vBJMZx54dCceSyS", - "HxnjZ5Qg59nupGGXVo77idUxfsiRXPcBbBt2hw3Nt99c", - "HxsJQAfgMFVcTqf7hfLBg8UzcCq4rQJdo7g61Z4i6ExG", - "HyCf5LyHfwnpnvwTQkfPWVdkqJJ2R2A8fBKb52m7cunf", - "HYW69eojAvAqiPfebT3S8yUTvTDHnssZbTq1TMCm5LfP", - "HZCUCLqV3P7QqG1oskLLMJW28zuckhxmRzEQ7UWaH2U4", - "HzPFqFKsGRT3Yvd5Wgfng16c8q6e1bDe3W48fZbuuS9Q", - "HZX4MWsSDzRerGuV6kgtj5sGM3dcX9doaiN7qr5y9MAw", - "ibwMFhkkeMTn9746FERTdb7rGuQwVcRXDbNYXB4QB8q", - "iMZEU6pbrLTCHZsaw6HkwABYvMTfn9pND9AqQgaEyuo", - "iwf4VCAm2WYfHMWkGC6p7PScW5vihfVrXs8UTnMuHuc", - "J1Avgbk11jXQ7YfXcLiuh7zdLGwYujyGVixHLywWmSuC", - "J1RpwhRqrLGUpuwazwHn5yVuUUjQXZWC5pVRoU2YqTYx", - "J2crq7h1jqvXZiyNeTSpi6S112WjQHMmQe336qPqB3cF", - "j2p9Ccp7FBBfNzrW1dtF64aBDZzTVD874dqe5ZrZCgC", - "J2VXfywh2oc5eT1LAtSApAqUVB1zJypFTYKTBdJg7BLW", - "j3z8UNavf2RXACm5fTkfmkhb9SZZDBt9pyYX5ZyyZCj", - "J4FGK7xXt6E5pfxBtQhGfEX1djdgsLNhdrei4s5ghSaX", - "J5dVAuWTHSppRogVgdinqaEHgkkzzKYWdkSRZue5zpvi", - "J5RKZBQ21j65Gn3cBBcFFtBaJW25Y3YEA3n1WjkKjNSE", - "J63rQazpR3qLHBz5DQLg5NB5xKDWAe3rLxGjpnJmZvmp", - "J6ypmUL27j46uATh6RCC58m3yPDqbXfpE55oGsnYuSQ", - "J78SNwDW6G86sMmh7djnBKGjewXNpjD74sJTjJ1iNgTH", - "J7Jx6vDZNfCHUzMAXxbdjfNJY2WXcVsd5qMtVN1Pua6t", - "J7v9ndmcoBuo9to2MnHegLnBkC9x3SAVbQBJo5MMJrN1", - "J8d11HHB1ttEf6wJpFdUhXvpyZefykDpAq2UDcPJsunW", - "J9Y9xwDkqFgiLypFoFmpC9MtAqkt7B9CTWrLUvyGZfKV", - "JAgqqfmUxsLzLxbuWpigwJ7Hz38vtgyzzt4eKE5K6nfX", - "JAXyzy7iCvCSTxyd2JwdTooQJAceQyj4Ajy92Nwn8Axy", - "JBtk3KGDoQXYedMDiUFDp6VXJr8MxY9tqXg6pZ8EkaT8", - "JE8vncP4cHCGhwJZQuzeBTfUVZ5tsFajkqUhcN4Ljk2f", - "JgcWmNdwrrmvJiuSo4apJCLx9MozajzKRTF5mQREiXH", - "JoeKdMCnk9rE2DkLnej7tw5repqdfCDetSLCUedhUVn", - "JortrVgBnTJ764kQH5HHhv3ozUpGUDPKqWPavUmjEuv", - "KdNhBD4WCm4Gd1fwi7Uf7Z3JD9KrZcnWWm8nSEZ6NEB", - "kffvkDohANNa2rpj8Ti6KWZctCX3Ci6Rj1SnGHx2r63", - "KjkPqUPPsYe4exTrHj6XPKuKcEmXorNLPuPWboQMSaw", - "M7Pcv3j8KpX8ZAkeSsvJnexgKrZbBAaMEcRTvf6t2Em", - "marivpF7DDv9RhGnBYrn7SZFuahFdwHt2pBenWfG49j", - "markiLNTC3FuWYGXKz8h9XpbwJbVQhzuV5U3bfpPc64", - "mETnAkTMdDN41d9wSPYJWDFu7xehfoHyT5py2thcxHB", - "mf1oPU95NbDVo1V4ca3QayhQg7WdS9iLWeEM88ex62B", - "NHtR8X7dmwtCagm1FuuC6ngQ3wv52uJYqFvA79G47MX", - "Qfp5wD5TwLiecZZP64cn3SwfqvF7W4fzo2tjEy2c1MR", - "qzCAEHbjb7AtpTPKaetY47LWNLCxFeHuFozjeXhj1k1", - "RAbGPTmaLVn1HkP38tqKYjGceejMWiyfDPEhenjH1Aw", - "rAEVgLDieWcb3N975fNsLbmpNenL2simANdvk35iLeh", - "reisen5FAkzw9iKy7RWZqyhRq5PrDVTKGAAQSB9McYg", - "ScN8WkfK7c5nmNvNh7SbFTQcNyw5poXv97h5KRFBRWL", - "SQJYmcjgo1bwJe2YxJwRDAH1JKFdrQM4AfLzuLi5TME", - "T6CVCqL6Mcea4wjRgvoZRkDSexzNP6fuNcyEdQZH21H", - "TxChgiaHwnkdT18sBnSepLE5sGk7vsQ4CZnhwiHUMQw", - "UdAZ7oz1WshdwyimF6e2VXiy1eSJ6UdHSRng9yRLtgY", - "UkQCtmg2gSygRMRJq3wHT8fZahqYzwRp2rHXE2hCTX1", - "URnkWZGiuB7jXbfCSuNSwir1qkn7sXjiSPeLPaXys7b", - "uv25bCcVy1tEZo8wUjWfMZNF1eVXtT7ycwzxu2ZHBAz", - "vav8fy4UyYKf91g9uFZybjwZh1VS6hubfaKyFtbYcvT", - "VbPq927r2eM2AiRcfibv9qdKtgbbpWJMCJcSSQjNWgL", - "VCRrRTgSjDLHvo6UQKXy8VQbNVG2ioHNUEyS7oB7u3X", - "VKoaYMffGUE92ZPve4wLCypUxoGsKYeo92F7BK1Rh61", - "VTAZqz5HadKsUWyavErx3hhUeaDPerPVDssjB69hP8b", - "VzbHiqN7E7PcT1fD9B855E3kWhRpdcq2QU1VJEWrrFr", - "VzZqDXSDF8KbfAQUvizj52NTjRg9cfXCAZ1cUJt5614", - "X8UDqnz9DemEwsVTmKcboZERqQXe1gNHRXAmGFQsY5J", - "xfCpo4ouRs5BP3WY5BdWhbr41pQxYGcXxz1sFyzPsZr", - "Xq8GX23YwT4pCroxiBS1KMLxbmBqmCRRFBb241cWsUz", - "xViooFwobBZE416moj2yFV6RJwGVaBDbCQJRfCyz2FS", - "YpopmpJ5ryYnLZKD7a2dEbPdPiiSLRARWVj3oAmgWLt", - "YYYYW8eKkmwQFhVGUKdBAnDQPuhMTpG7zwm9nikNndC", - "ZDCJDkoBMTXpf8zsfQzbLeTfAus1qaxiFHnANseQrmA", - "zi35ABZ6Lc8L5s4nVt2qzAHJCAZZV4E2aYXL2Xq9aqF", - ] -); - -solana_sdk::pubkeys!( - mainnet_beta_validators, - [ - "12CUDzb3oe8RBQ4tYGqsuPsCbsVE4KWfktXRihXf8Ggq", - "12oRmi8YDbqpkn326MdjwFeZ1bh3t7zVw8Nra2QK2SnR", - "1EWZm7aZYxfZHbyiELXtTgN1yT2vU1HF9d8DWswX2Tp", - "21REqzFbJJb7itcv2QzkjvHuCR9PyzXV1uw9251JZq1V", - "23SUe5fzmLws1M58AnGnvnUBRUKJmzCpnFQwv4M4b9Er", - "245B9WFHUGuWycSXHagHXwsXGcxDkNYfxWBaeh7vAHDU", - "25andkv98haPs8LeocDfmKwfNnpbNcHtsWoHDSBrWGYb", - "25V3EzQTGCSoLhihuH7f9jjyim1sxH6MR8MUtRLtLuoa", - "2B5wMmBQkMHu9V5JbUyJuf2mJJUU286qKPsZzvQQjTNQ", - "2beSsAmYWPaNJ6GShkAECv617wmGfeH4sSuRFBYYX662", - "2BHDXBCcndLg6oYu7EvSd3TuVJjUQX5xmUiKb8fDMjRt", - "2Ce1dmtdnvgDwD1MiZjP9wwGup6j8H7uXGuGMa9uZo5v", - "2D2v7sMqDuq2ekZnFhaQm4k2ErWHemZQuYf5qaVTPFmg", - "2dxz129YxB1xtf7Mx6HUT5JspexArNNtQt84FYueWZV7", - "2EUh4NtRwhJ69UUca8HuGEcABsn1MbvufqFUDF8XrZEe", - "2Joxdac2pgGA6xqBCChWKZNKhWgnv6vkuEkGp14JFPzT", - "2jS8AX38m8F9C5juToW1FmTufEbb1DfDzZJj9HSJcWwo", - "2KnfYVJiAtxiSPfHYRzTsGGhUAhDTNrJXWn7n6K6giJU", - "2LhJjdjNic2BcsRLN8opwd9KZSsabebQMnxj2PkU8ADQ", - "2mDrrmhSzpSyaF12izGk8hnFjtKCGeCFPwQHpRiJDby2", - "2mKEUVkcttHeMeaZK8jjwkuwGSdCBm23xDgzXgbhTdPe", - "2NJZ1Ajcwtc7hZdVXTXrh2SAiAXnFkVm6MWcGjBZfPkS", - "2nZo1aiuRdTKYCfuoLR8jHQY1TxkTQxCw3d34K3uQkiy", - "2oujYrRmtDDTF3b3JUgsZ34TkcyrozMjgRHBQE9R6K8i", - "2PotfnmMDS2mdzoggBnNhNVu5NxZsQB8RaxjbDRPJhSA", - "2pRZBEB1PX12cBAbgh58VfzTPV4ePJ3txXeDTM84ejbZ", - "2tKR4mX7LzhjfdNsR6HfBaDDh2RM3wdpUrJqUU42aJTc", - "2U8iE8LGdAqep5y3toyrBaZF6DHP2kf3Ev2vLFggJqiW", - "2Ue9zGmDnvYRrJNEjuAdNkbbickw6fKWtbeNM7T2rakg", - "2us4ysyNvYJHkYi7CtRuW413Mwi34kjjFQGhZDch4DEN", - "2UuVd6BMW97MRnj7mCpq8PhYmqmUYuojvDkqWstwASCm", - "2VA3q6DbiLjbrLgnkiZ2fdyuRyVBkYRgqBDwA6qYiSDD", - "2VAofLE2bYNM3ZPGfn6dJh2zqtnmNdD1bGqFet8mVYFN", - "2xte5CBkCBEBLNviyAfvSaTkMy6tvg99Cy3XJj9EJJs2", - "2zAbHUpE4MRgEwq1MWh3i9aJyzazSjUUPrmhNViqQn5W", - "34t5CmGFfVkdpxQgKbAJKje1NLXa1AdWUerSjnomPgxH", - "34viN9UrGJaVabrrSZDs8MnKwVt34nw2wv4Xkwk64shV", - "35AidZv6XxjDg5NNPaKUdzUxv7C2Qi9k1tF9vhMgnHhR", - "3A8F9LjrMgY37qZVAhQ4ccWmrvpQ3oosXfATUtV9ozDA", - "3B2mGaZoFwzAnWCoZ4EAKdps4FbYbDKQ48jo8u1XWynU", - "3BKnjJPKQrC7zw7X3KtTKVtZtjLoLgzeJ9xZoAtZyVci", - "3CxJofVghT3nbqtrSWo3oMQTFynpNyqtytBFawpAXi8E", - "3fA6TU7fQCkNDDKYJeCY4Ag2gCatEsYnYL4SpkSDYfCw", - "3KNGMiXwhy2CAWVNpLoUt25sNngFnX1mZpaiEeVccBA6", - "3LboiLyZ3U1556ZBnNi9384C8Gz1LxFmzRnAojumnCJB", - "3LKjD9Cb8RKKbmwM3LphHEvfZdjEU4rAFGDDUiVnuXhJ", - "3m4ov8U9Gccm8Wmkmuk4xJJajF6dSUQWZFDp36y7zHdW", - "3m5QHq24vbPVhtbcHbaDjvij58WExvfy16UgcCPLfDXP", - "3nRhescC7HMYC8gKti3ENiBe8LnKZUs2gzYPAjYniQCP", - "3nwmifffA54NDWqiZH1oYMKHaS21Evmy7rjPeL9veegs", - "3omj2Ajqtb7ZjCwxaYPXPrERhKDnwQRFr2ti7F23Kd6A", - "3RbsAuNknCTXuLyqmasnvYRpQg3MfWZ5N7WTi7ZGqdms", - "3rqEEEGjHRyndHuduBcjkf17rX3hgmGACpYTQYeZ5Ltk", - "3RXKQBRv7xKTQeNdLSPhCiD4QcUfxEQ12rtgUkMf5LnS", - "3ScqKCyAKGN4B27S1mFNCCna4cf3ZBZf6diuXNPq8pBq", - "3T2nqHFbmexvkhEo25SKnJsbaAjuyUGBjvdttczxDKgs", - "3VRzZfDDnNiSBzW259vKgtq5x1E4fzkvs5SZcVtpJEzj", - "3vYPCtncFxQ1RVtSpB2HRg1udHfeVPWPpWALuJaMcLx3", - "3xGDUST5CKZsiW4L5PPp9E63X3PdqRvCJfDM3q9EYcB4", - "3xubywCu9F3ALaYRKgp6RVUnQZFf4npNcDZCH4Qjpmmd", - "3zaPajeDw8FxutdgFTUSVKp1cxWFqs62dtuCZNQ18TT9", - "41iM1ZT5WYS8HgweopShefLJRfDD3jbB1MMJZiuEemvE", - "42xkjBQvPyicSdCET8eTWwJayTBofFLGWyCiuodd1SoT", - "44Bivyyp6Jv3Wm4RfJdtpCPBmbEXxvyotUoMDg91ZJPo", - "452L4U6HbzT59EP9vLyPxddF99FBBZ7foCrcn5A9HLMK", - "46yVA2WVP6ah5wLREZGHbGvvPaM55rcwDKDDikzn3BVV", - "48Dactjx3zuJujtBHZ5cd2w3maKFFGsKhn1sXzU59VGK", - "4asJHLR6DbifuQK2MRGNx9iHujYDYkQ9pqQXsmbc7fyD", - "4daH8Aotxpk68HsMvws3P5AQL3F1gVTA44jqLaB2GuGx", - "4e2KvSCgot2RGXsExfY48NdfykQSjgozV5FAXv13bUn1", - "4FozAhZhAo8ZTuzNHeAHMDDLqWmRwioWBhFqybZYHamV", - "4h5muqwz35tyPQdAXkZMyVM5cnGN5oXouTZL2AFA1Fjh", - "4i9CE2ewTTWwJkdMvNcia3D4yR5v4AKryae4nxeSULwL", - "4JryygoiM1j324fYkeBzcQDcwRfd2WpgkEzUePFj1rJY", - "4K5SSpWHqTbx5N5Ytjj9iWXNd5zZEZ6fkwjGA2KKafgv", - "4Kbcyn7JVPAWLRLPsNGTPmcNMvCkLTw51ZLRhqsUC6jP", - "4Ko2GufbWc8hhDD9GL46He1Q1Z1s6VFfBZS4RX9yY5Rt", - "4PRFPF7f9ERz9azkDFSFfgpye6yixPENCka994j8mQbj", - "4QNekaDqrLmUENqkVhGCJrgHziPxkX9kridbKwunx9su", - "4R8aXMwJUdE8WWtM7yE7sPFHJBfPBRd5o7ERVeQE7DKB", - "4rhWUqqNbdoVsGGw7P6Hzc81FB8C9jgR3UGF7aUgKAcY", - "4tS3UZfuRHzXuPenvErtRPtnZfY1KHhT96JBCQsLzKqW", - "4ULWSuaNnhQntP3DVxg1xa4yeNLNpDnAw3gTtrhPHzEA", - "4w2p2n83ter1rkk7Z6r63z3uNBKuBXzgV9KFDWBidSFQ", - "4WgsjJxehCavDYXEMTBQX91KKh1szuQtzksuxZKgymq9", - "4xp7K2vkm9LnJh1aCXjJyyF6XxL1u5gmYkrVCxHU6Cnw", - "4XspXDcJy3DWZsVdaXrt8pE1xhcLpXDKkhj9XyjmWWNy", - "4YGgmwyqztpJeAi3pzHQ4Gf9cWrMHCjZaWeWoCK6zz6X", - "4ZToBgveZ5m8NySrDyPA2fiGVRVBioaoMXD31KGidm65", - "55rEq5xznJEMEShWB9GFv5WNX5NfCZckLZbXXDyW2seb", - "5cshESzkc3hmUA3qnp5ridF6WTeiVVLUYkZUaCPYfbid", - "5DhEjMqxWWAagBywA6kL7EczqTnDGvPmDfseottjyps4", - "5GattKwm5oBpDJGgdL7ZZfCMthoETwrZFmQMDK5eq86a", - "5HXxjDZwm7MAZAm2aCgGcGRr3SKiwugcQymoByyd7pfv", - "5hyHG7SnmJAHZmM9shuq6BXxLSG2EeosMH3ZohtaewFM", - "5iJmsXsq49ZqgP9QbP2gNQRU9C8PhwA2gbgNLdgSHbjh", - "5kMJh1BtYFrvr6EP56XjoCZmyxx3by61dEvGewYTMuxE", - "5nU3v9FRnmTT7LrGKRj1reQoWWHHmPj5sfh2mTSti1uU", - "5p8qKVyKthA9DUb1rwQDzjcmTkaZdwN97J3LiaEywUjd", - "5Q1tTkjCtYFAtyZ4fxYYND8Ru65LLPuZSo8or9Keyq1h", - "5rNErxSxMj3WysMx8bC8vHkbrt9QmwMeG9H6aTp71485", - "5SpUnGmQBUYVWJgagPjgyvXW4ivYPi6v3n453Qi81Lox", - "5V32oyrRmsnuVdC4Jv178KVBeehDQUuk7U2D1YmeP6mS", - "5XKJwdKB2Hs7pkEXzifAysjSk6q7Rt6k5KfHwmAMPtoQ", - "5ya8UPujuXN8cys1EaaqMMH3auby3HTHZki73Q4Yfkff", - "63sJMcjh8r7W1oXjrNZrG4nc4UX6cQVonUHp9vGDUNdW", - "67iXZNZ4ytz3A23WueWr5B23WY7yHdESdRPGbVaPYkHw", - "67joanjyAoVmb9nZLyX8p3Gx9tAxzXaUgHDe3kaUH4wf", - "68EWE8SmV58oRG9JJELNDt8Y6MuWBbfraoT67KFw5Ath", - "692qK4TkXnrGfDZfoSq9aFfnoE2WNW5TpMRnN7M3sumF", - "69QvoqgDazuAqD4ygG6YsA31HBV31L497XqmQohF5ajH", - "6BDNnr38moGRQyvx1Ehs9cM6tJDFK7LF6mUvLziyNrzW", - "6cgsK8ph5tNUCiKG5WXLMZFX1CoL4jzuVouTPBwPC8fk", - "6DcjiCqt6E65w8P352JvAN7qDkdQc7YQJHBrGf5aVAze", - "6GRLDLiAtx8ZjYgQgPo7UsYeJ9g1pLX5j3HK97tFmtXb", - "6h9jyRgfpmgXNyaWpbDpbxbCoF56WEbzsruhMwDn2om4", - "6hpMTcU76pCkSZHG1qdfw8ZrM9rFwFCpmKZWqBc5VXr3", - "6iYUKnywYPEZt58hYs6WKA5tZjxL9MFupCxDkygX13dm", - "6kDyGMHbuWekkcquroYNp8VRL5pQiUzEJ11gJ75qJsRy", - "6kfL3zErU3z9iofwdg6iM6UJDFZaVJNguAwy8SiN82db", - "6M6aAEdhcWZGUeaRdc7cd81YFZ9UahgZP5D1x3MzXxmJ", - "6mdtNmZpSycAZKXKy9JkkfdEZCMcnuyuA7fzdnpUohZr", - "6npqjzgFPuL7dKdaUsgLwKokWLDe3wFyHeDaVT7Pro3d", - "6PbhWC1XRHsW3npzCHm374yE72B2mbjBrXdUAhouozqm", - "6poikjtKFzySv2zrfEJCQorTDJWmoqCLPbSXeNLHyvL3", - "6pTM5pLcQFEzCnd2GxLqLm4jL97ZL8L1ThSpR5aVRfc2", - "6RFbeXzEyabceq71fMBLuBVofWedpZAu2nK9vNbZiqei", - "6RmSMaZbyb7SGKLp34MXY2qkFePZh41Frs79xJgEg5R6", - "6TK3XwxN4XMEM9urq1n15CQyF1Z19idts4x5Mfibhtq9", - "6TkKqq15wXjqEjNg9zqTKADwuVATR9dW3rkNnsYme1ea", - "6UFmHMgP4ErpKrdjDgya1gAfHmcC6QhWK9w8wBT7iCNo", - "6uHvWHjBYiMowwKUZ5waAc83x5bnLbmGfxDnXPVQYorh", - "6UvA3z3sKbxGXobTQngyL4iVX7kV9jeGYmCUGRMYZqcK", - "6vi5VzR8KURahz7WheNGRTgGWHnKJQiKkqNbfua1sJiC", - "6wsSvrZPbjWeNNZ92KWtj94pdHj8v8sRbKsu1ZSpztpP", - "6yf57R7U1J1VXszE7CobdYEWQNJMPRfWEgGfaRsVNk32", - "6YPgmQm44UeSEeLU4NRP4fE5HWrEoKupqtRMK72pDjbS", - "6YXp94DjBg2cP3tiVjHhgZYLP7juG62GxzU3yZFE4zoJ", - "6ZomMAu9XSu9fzkRjqM6HbAXagw6Jo9fTsfsAADTZMSp", - "6zxkTupZL736phbbktUkWQSqWTzeYKbTFoKMENoNnJW3", - "72FqmsqNgpgF4XGueM7Ys8X7xd1ZqBzWvUQUq2Rv6bBv", - "72Sifwyudib2XE9nwDamapVEJr4rZLFthLtPH83ScupR", - "73A8PnqdHraWe9W5jiYzUBPEf4giyTxUG1CKZ6HkXbuz", - "768DzddM8MGfosYS5JxjzpY2FcnqeNHUxMerFQHWmwKy", - "776BzpbpsZU1rbCkNHizEP5r8RE8QL12Xqm49krkLPLy", - "77xRWv8Z3kaQpD9K3Den7YWJ7sxsf1KTnw5MdcM7Gtnw", - "79BLeiBD9r6okMwEPW3zHAviUJFwCLjTsK6HTPBwrN6f", - "7aR6AjK87ehUxwEJrPpnoizUKtxJKxqZCQCEGD3h1Xgf", - "7cVfgArCheMR6Cs4t6vz5rfnqd56vZq4ndaBrY5xkxXy", - "7CyNBLaoav9fZhX4D2WGrL5XCuMroSgDut68vtL8NB9p", - "7DBhzr38xGJeALbZB9bpA5bnzVL8N9oGCjFfWuN6t8cG", - "7ek3CDbxpGRdCVTJJpj6WPHmZrJqBCQ2RBQoqLHitx5L", - "7Gjec4iDbTxLvVYNsRbZrrHdtyLByzdDJ1C5BmcMMBks", - "7jmCjQt2D5MVvSz7NhpHLCXGsh8Mu3qeBbA4LJAf3Xsd", - "7N46n4N3tiX4AjVKBDPfAuxhgirAgDFknn5pkjYj3xz2", - "7Np41oeYqPefeNQEHSv1UDhYrehxin3NStELsSKCT4K2", - "7nYNfGS6VVxzCZmfbLGpsXYFm2LS9XRrva9hZahFmpqh", - "7oGVeZnNWa5yDH6V6ec3Ya1xzSFykc62nXKDGhnbphuY", - "7PwCuKPmGF3ZqWHgn8zXPtsWJ7Ud2q1DFggRkzctwJnJ", - "7R3t8NAU7NDAd64KLz62tj1TaFZLmSyVSMRJX8VT8Agp", - "7VWgBZJCLtuCTGdWoiWPrVqY1TaqiZQzEqmArzGzrwGN", - "7WLzboF5Bu9e26MvLVps4rPbSHBgme4J1w2Hr9G4WW5C", - "7X1kgrfYRwFd94yyE8tvsQF5aTFHdmoLXnG4q79onDAg", - "7XSCAfoJ11zrQxonjbGZHLUL8tqpF7yhkxiieLds9mdH", - "7ySQKwtxuvxQkhW8rKsa4Ch83tdX5fzfpd5hu6Av66ur", - "7zPjirsZ2GLwji87WB9EPyeLXTzigjeVAxH14nB1Ss2E", - "81JyjgUyLbqs2f7iSvrEBwE7Grj3MsQwULMGTxXKnLvS", - "81zNHWkYaQRL3TWHSNwzX6T64yUyVQ7qXzLLxvaaB6b3", - "86fVAWdCDyrSHnv9y9dQCrfQCY5CrXptLP7gL5PyUDxR", - "8c95uL2WKofQGfr3rAMZHmJ4V1UJW5puTmpw96n47MX", - "8CzsSMYcmtFmcGpYYv98kcoQQaWQLVtpQRUzEw6awPHU", - "8D5rQbJD9qLNJm9HyTjFWV93CBc29ozAdGUia4hyMhw", - "8DXdM93UpEfqXezv1QTPhuA7Rci8MZujhsXQHoAsx5cN", - "8ebFZA8NPLBZD91CwsG1HWQsa2B5Ludgdyf5Hi3sYhhs", - "8Ey5FDayWYgJdVoquScT2hJDKWk7nQQfqzfGBt1emJpx", - "8F75kvPrr9SVFDDbyNJQ9J8sxpEXDNh481McKJ1YzQB2", - "8gcMmaEAXfRZKcXHeHV2x8R1ebb78inTr9xhhEuNNoTt", - "8GLRbAstsabZuZUx73AoyfGi1FRCWSUhRgMugFyofEz7", - "8ne4sDgaaMtuwY1y4BaMYSGKXpDRVc1Po9PsJQvrZPMs", - "8o59jbS8MEqSd1J72ryL7dghg9djh2BAUtpkZvTTYh4H", - "8pyp3vfVPRziYdAYEyqkwytdBbdVbQmHqfQAVDcRV3w", - "8rVubWZEYjy4YfMvUr5CDPg6YgdFdzUfZtfw84cxGjaZ", - "8sv24V7cy7tyFPwn8nqAKXiigeNmgYACoFmG2z2XBTZw", - "8tZuYRKd5kx4tNsZMZHA9ovsjKkQWf56kfe7ycLees9B", - "8VAyNMaz9DFLNxSFrhjiusKCcgQNKgnByiG6KfeCP8vE", - "8vnrJNMDERZRwWgUMSqwLyYHEPkQQg3Ww6BM9AH4uX5R", - "8W6wYH4cQKroY9ymP38DQeC1wV8b92xb4BWT2foXSvGy", - "8waGfnuaHHUgZT19xQo8LWsAY2CSrXiUMeMDUUrvkeu3", - "8X4SDANraPWJYCDB1ZYCucraB1TKki7vTFcJMiSrspTY", - "8ynefSJ7MVkC6VnMdM9Cm3V1F57fiYg8ugkfNV95X8Zx", - "914RFshndUeZaNPjf8UWDCyo49ahQ1XQ2w9BnEMwpHKF", - "93P67u58qai4kT5XoKX4Ti4g4H8nrgJ2PKnKgCuR39S4", - "94HgFvsD8zm7UXJ5KJxN4zW5nsdhZWY2LFREjfaFEHwR", - "97MtLX5ajrR319PH8iLnctBpaLFoT3TNuUAtZfZaEn7U", - "98vNehxpVCPz1t5RjnZZVjxQ549a2VLUbkpNwqj1rSb8", - "9bLEjf8SjumDs28WqUfoSnyh9Eg2VwQZGMrxxrWhvLWo", - "9bxGPEvFjGHqpAHMkm97R5d8euFnpJ3ws83tMkTbcBUJ", - "9CqDvvGvSNVZDo5RskCAv4fTubpFCs9RLTrjUxEYrvNA", - "9cYyjirWYs68YKw39r83qXv3rQB52dyviteRDKrDX2GC", - "9e7XGRqQqEvppx4Lkj6P1S7k65yWQpf3vcNzWecKSzDd", - "9FXD1NXrK6xFU8i4gLAgjj2iMEWTqJhSuQN8tQuDfm2e", - "9gFxqsXbFyrKXUkqpAatonn47uYZ7sEZSnMxhzQoXrUJ", - "9gJT69qJUibNmfnAPBgsqSmLqVxc3kxXpw1Vk7APDrso", - "9iZV3mMdBh9y17hM3eVXUVuH28pGLERSJBq2z64yfreM", - "9JJQN1WpJ8QvH6XK1xAMbSpgHSiwqBgWaeCh3ViEFmtN", - "9jQ16ZjBN1vmXn3dpRDc5eZkRPU1kUTp5MPnJuSFWb1U", - "9JZXYs5TisLa6gra2PDuNibbi2979AZuXNY9zSVGz4UA", - "9mfDCev5UYzN15XS2AyRPXbcrDJ3HL1jkXj3mdP96Kam", - "9mo138RC4NbMYvWaVUE2cYPpY7KCCNGvgHhi4cVuCyM6", - "9Mo3ap3jpuqQpLi75EsiXLWfTr1cbBhrJNumoq1wnVp6", - "9nEBir5mYz5yAnAtuZsuBxwfC7SayWZTMnyCmmTsUknf", - "9NEsaMNVEEPHCdgxUzeziZdgx85LS5za9LVs1rQDGBdC", - "9nkbwUu8kVZMPSznrEkroG8bXHcgxPUTQxFbVp2oXYQH", - "9of5uVqC4EYZ4LLJzPecynNM4GsQWiT1WtHfA39VqcCR", - "9ppJrpsbbuGNjiMhhD52Ueco4KXUzVfrtNQ6tAcDab4f", - "9q16BB7WGmBxf1nJTdxH5zPnBUhtHqdqXqRFjSjuM4k7", - "9qbqAdFqJK4MhmZPQjbRUxRUi2NTpevAiZ8wj7SiCiTQ", - "9QEY6sXPc88gt1jNEYUC7YWceWV8nRuuUi9WYrDngro4", - "9QsFvmFWH2weMKYivw31wy6qCztnSEAgbvgAA8gMoUWH", - "9rVx9wo6d3Akaq9YBw4sFuwc9oFGtzs8GsTfkHE7EH6t", - "9SUf5VUSACNWW5CgbLs26hfezhUgeR5pNuTB1ZmUFxVg", - "9uAtx66puPQZLaP6fMKNKKyRtGzonhaUEdbVopgeWcfS", - "9Ukj3PkyD3igEDJGt1QTj9ThzjK6hMiadQfa3gm7kjf1", - "9UsSQ9m5QemVf9NFmKncDDXGFGzUXMiFay9Fv7rUmjtV", - "9UZ3NXk9jALnrhbWz91PXWya4Hvi94jceq5nojxHiKgL", - "9vpYXvRdqNJD2YKRZ9q6Xm7fh4FdPGuc5PBZSusv8vbi", - "9WuDnZMufE2nsuWsTnHjJsjavuKtswTpCy3i4A5kKT8c", - "9XQyJ5emdYVDB3PjFDCmXFG3G4cAbPHJttF2hJczhZB8", - "9xsgKAU3pyKZZddPXdh5wLRqjdw2Fc93BL41JszhEpZz", - "9XV114Dg7cQF5zbxEoEnTpuYXR9TgdjHSimZtkzh4epF", - "9YDu59tKDysB9zT9P8cgvaogmuy64R1Nxbr57QHztNrW", - "9YGn24qD8ZCU1EKZEsPLSEv7SVAJ4kpbCTmj7fR5TXYv", - "9yWfnPBofnWjXRvfEKLioMb4VrCkwqcYBbWj1uF9P6X8", - "9z7sdEnttp9T9bzoRZumMcKWCU76RdmrFPi42km7Twb8", - "a1phaKk6UbG1P2ZCpfMVFUeRM5E2EZhGvUjqWHRsrip", - "A31PGH4i5xGn7SHWpsQRhpBYUwanRuqNrHBp8bSeCSEr", - "A5dCbrjh492SU7fg31wZd6CNmz2NYqH1gEE219qyXZbe", - "A79u1awz7CqnxmNYEVtzWwSzup3eKPNW6w2Jrd56oZ3y", - "AaDBW2BYPC1cpCM6bYf5hN9MCNFz79fMHbK7VLXwrW5x", - "ABC1U4cf9DZMwqy8ktEr4WJj8VHmVBQibbC57gEJthwY", - "AcHVKQ3LoPUN51Zx2zyA2CeSZJUR2zJ5jsghTpWFgmHf", - "AEx4pxCHFpsVgZ2X9t38bt4CouZ85tXXcghjUkb6ypv7", - "AfDqsQKrpuDEHy65fsHMzVVeh4FcsRomxoe5nDLPERE8", - "AFNiQnEvAqjFJizDtSAh5ypdXvQDRxHN61kcect5wNEx", - "AgG8obWYeVY6nSkPYqDHXfssxdcG68GkuBikkearYRv1", - "AGsrW2sp9mqNp7g9Nqw6g1A9wMyDYysqTN6d8oaw2W4s", - "Agzs33CozCnr3eFvyHcYkb46nUZq4dL9SFMV9CNAxfGR", - "AHg5MDTTPKvfCxYy8Zb3NpRYG7ixsx2uTT1MUs7DwzEu", - "AhL6bJ2BF2qWSP9aE3VnFZFm9DXxWdfc4PjFBKPncsrV", - "AJ6PKuAJmACTpB4tLPm61u5ScygG4c7EtU5HZmCQ7MDA", - "ALiZQ5XboU6qTGKSP7LExokaZcPGVYvmdFqqEw2bCJWp", - "ALp2GdA1eJV8vZHMHazCtTxNXe3BLUSco9LDASgjDs8R", - "AmhQFcGvH2hjkucP78rn6GMKSbstYwyFpCDVKZUwBGrG", - "Anara9qw9KCKMFPX19GUE2drgwiw49u2pQhHXwVRukhn", - "AoUwfPuiEek2thVRDhMP7HbQb9rguyab4rDiz2NAfwwA", - "AqGAaaACTDNGrVNVoiyCGiMZe8pcM1YjGUcUdVwgUtud", - "ArA1pRBW7WFcx1StiRpwhktiXkdQTdoGSj519hzr8hdJ", - "Arvv3uwEyDPKckw3wEFiCq9hgxMw8kawFU6doxFAWGYR", - "ateamuvZX4iy2xYrNrMyGgwtTpWFiurNzHpmJMZwjar", - "ATwrKSHdF1JptZDFd2wUeU8reP6ftp9P695W9ipdB6TQ", - "AU8CBLxah7B3HQE4rtjfkRDmqEGLqu1xKUPLSytQ8tLc", - "AUa3iN7h4c3oSrtP5pmbRcXJv8QSo4HGHPqXT4WnHDnp", - "AUgbNHRcxPqfmq3CXQ5bvy3BpN8KZt5LtXBGSH3gV5B5", - "AvAivvbUcs2ewGpj2TxW39BXmA5t6d9ofQZFzwagqAzb", - "AVUsR5RuxBcZDftuUNQqwUKwx9puBE5N1zmgLQZSxiuH", - "AWHfhBSMN7rX7NEDrKNfjnUyR7W1xpfistTy6w9GqT6U", - "AXXrLQ7bVy92pPxW7heQkAHfg8LuJ4uufUWCQgH12rmR", - "Azg1hC9mg7pkSq6Q5sAESsBsrxHoUuyRnUYSCJMJMdup", - "B3SBGpUurKfrMAh3vykyueokU9vE7EiGDkvGFzxokQoa", - "B5GABybkqGaxxFE6bcN6TEejDF2tuz6yREciLhvvKyMp", - "BAHNFqttxYMMZUDqMm1JQPnxkZoHLnpash1ouM7pnLEA", - "Bb4BP3EvsPyBuqSAABx7KmYAp3mRqAZUYN1vChWsbjDc", - "BcMg5hjgLZF2mCJ6L2ah1p7TxHtH1euPWP1kZs3USRyC", - "BFMufPp4wW276nFzB7FVHgtY8FTahzn53kxxJaNpPGu6", - "BfVzQge1z9dSZ2YiGyRXoPRUvowe3S2kvbLU61zXn1cV", - "BGBxrNWZ9HDBQoXA9Zq6t4auRXa59qrLQkiTGtZK6FU9", - "BJafMGt4t8A9BENBg9EcXEAqUSgBLaQZujQqvrsGMgtL", - "BJevND8rrW5f9AHSysSGTtDWKcARxSpzTyDAvCm26Qms", - "BLPBUAuWmjTKT8rF6nXnHJCcuK4ZonH4xdYSD1gZiET9", - "BPX9WVx1MjVpSWY9fo3hGXfE74yKXcreS2XYKjpiyJfZ", - "BR9JfwDSvtP87kdJxeF5QJPCcj4bdmUNVDPtsK64DCkR", - "BsvtXMu1eGKrAhpP636EnNG8LWddxqmCDq8zcEG8CwY3", - "BT9ZFvsDfX6WpLFqmWEYuLuE5i3SxzdSJ1Vzm9arbRub", - "BvXzmS5rLW89nHD7K2qVjcERKigDdJ8Xhc74MQZumj9J", - "Bx6R7GBNsFCt7KJUZw5yrbvdhL1EYcXPhkUBnS2t3c7E", - "BxN7s13iMFRCZEumBRzUpH9E25V77dL7VgSig18MYKbm", - "BZBKHmW1DhBaAPojxWBQ26vGz42Y7MtNviFZWpc6nGLb", - "BzF3s3AGgYupiL5Mhbzr1tu1ySMZSR3SXU4DajV1Zwv9", - "C219S526JWRzpPUm3FfAzobwZMDuo3DM63phtJpqAz75", - "C5oTsyGA1gBvgWpvS6EaWGAgEKDBkMpQaPeLTiaLuYKi", - "CakcnaRDHka2gXyfbEd2d3xsvkJkqsLw2akB3zsN1D2S", - "cami5ixFFZD3jLdX8Ef5tu8o21reSGoE3GpGRrQyP4z", - "CBUGET5PnvLc3HvEeFYj64iTvdKhYV6pujTPDdDh785K", - "CcTtRsmLJEjqsv5iyfXSYwjaUJdfrRK7AU9cHMnQfTb3", - "CfBJ2yK6hbRD3mV5VoMux6nkki3mYa3NCmWWnfTeKw4B", - "CGoT67sSerk9ckwin6yY4mna3ymLxxKNqdYeQZ9xNdkD", - "CgwKP4kM6B9giquCADDXQxik7BJR5L7m2EC2ntPnQoJy", - "CgX9oSHcpXjKKxUpLbrgNKWrk3ff4cQidfsf96AkMBke", - "Ch2UBdfwRY8UyAKCBzYksu7QYwjCXprkbUo7AY9CSRyS", - "CjmXSapt1ouz3CZzgkRJckBEwMSo5fVdVrizLeRscwYD", - "CLarKkpJDBiJYLXqKLVEL8VJaAxRHnWRyjjxAunCFJ41", - "CmoYHsxUDcReka49CbnJqoQ3y9hHYkCoTBZ59jA6k6LF", - "Cn2GFnp4H4mejHtR4GbV6ga48qoceZefzxNU68PxCcK8", - "CouDacpBtF6mmN5K9aXyVds1XRkmo6J4t8ebFZxAecGh", - "CRextgJEiudn3vzHZauno3a8BpfdweYEdLEjhpZ8C7Cm", - "CsKpHvEjoSkdNduEjb7mfuJbzRKqc5ypde4yUW4iGMS1", - "CsqwHrSUAWsWpN5kUcjcv4Nsq5JtgFiDJTckaY1zuXPf", - "Cu4M3yd2LfMoGhmYxKszhVH18SPgt6TQvqnE4AWjNKwd", - "Cu9Ls6dsTL6cxFHZdStHwVSh1uy2ynXz8qPJMS5FRq86", - "CUPryNhYfF8ChYyz3tahM84ppX5WSpvRxWqP7PEHMX36", - "CVAAQGA8GBzKi4kLdmpDuJnpkSik6PMWSvRk3RDds9K8", - "CVRr5oHCAAooVbYze7CvXtRp4FUtkMCSqBZU7MVu8v8e", - "CwhdMezLucz7bcuWzStpLXgrzKGC2tBBiaVmJZjfprRN", - "CYkkaM5KwoxaFtZcximkm1DFYnABdiUUUvJg1WURDRsh", - "CyyXgFh1cQsrrqUvwDTWFXKFMnSe2H7H4VgX6uEkfBL8", - "Czc6nGs45PPUdm1jA9MkBfdxYRrZbShyN9rNj3P9chSG", - "cZCvgqgrdX2LCScVku8CprMnAUZtSicBDJ8eiowfonn", - "D1KH1UwfTLaBW3NubpvNv4ze9S7SKW6jd5TLdrwZgLP1", - "D2RV1q6FgePVVjrMa7AMzVbvvAeg5oS7TAV7qdNKSDsX", - "D2UwKTrNJGNLM1h66qjoSDTK6CLcPSzmga84MFuiWdiS", - "D2Wa6JtXeyqFMdoacpKMo86Pbr4YpfdVCtAhem8HjqfF", - "D32cBNvo9qmMyMSJzWqDPQ3ujYFuW9HHNjVkwxspezQr", - "D6pUrfgc5ZyXSfgtCBYozydRSz92pse1S7AZP58muEYk", - "DAHJgPKdmncYW8DmY6meaU953a7SktQ7eDGtWduC8W8m", - "DAS6zKbzVe5DFSwyEgo1TisuWt31HjBdZxzgBF2ASiju", - "DdgotKX6oyHpadPbAuiyAodHh3mk72SXBL4aeg4vLzZc", - "DE1bawNcRJB9rVm3buyMVfr8mBEoyyu73NBovf2oXJsJ", - "DE37cgN2bGR26a1yQPPY42CozC1wXwXnTXDyyURHRsm7", - "DeCcxJU8AqxPRZ27wrKYKRgmNHwCUK7MvW5XPGWh8WZF", - "Dfc73Czi5K3xa6yKMq98LHJx69PDsSzUvSdCSSqr8NDQ", - "DFKj3e6WeQmLxQkRBHq7nqcEXjwkcfJGCt22VySeDiKx", - "Dgwcrprgu1WeCNEVG2stkiABqWjfSFfBuXeMrR7qwJHp", - "DiFeTctQSaNczJNmZ5121kYqLaBe9wDpM9sjCzTELJLE", - "Diman2GphWLwECE3swjrAEAJniezpYLxK1edUydiDZau", - "DJHsoHQvqYjb8G2Ni6XSbBSHxmycMAsZksRDytQ2bntK", - "DkycekX1rxCUr9FtBHfacHEgCTfRdRLaKYTiz7fXHMQ7", - "DL6URBwusvYUFwEYZK4VEaoaynWSduUA9e4N7WDuZawf", - "DM52rUKVkCPDY3MFmSL76XAuhB5ZN7MuogAiQtEe1Uvn", - "DNWsTLvsMixgUcbM93437U8DWmJ9bZikQeBxQLHbeH5L", - "DohaxzeUj6ma9shCykxGxi7FbWnMyW9hzNjwQjZHEDV7", - "Dq3piY2ZcBvNN84j2EhDLtTzRAw95za7Eau89pNcmSd5", - "DqBvkYXi7HjdaKz78yakiDsaGuq1BKrQi3Z5JV6STctz", - "DSV16KKYW34qjxTBcTzURTyJYgw7qLq4VLKq3UavQKCk", - "DTF5DM36Jc4vkVPJXbSm7wRLe6eeX1UWo72WQhxKJpR2", - "DU4shVYTQz4Pf1RXR3ZMNp7Q9AqLK72sx6b96UxEpcC6", - "DViARWAWKkxAzp4UCgbw5B9pLSrBY3PaztFErcwgVUKX", - "E1SFkvPjU31xWMcvgnX6vhGvfRvb1zXvHFkqmQNEGZKK", - "E6cyDdEH8fiyCTusmWcZVhapAvvp2LK24zMLg4KrrAkt", - "E8swCwkKkQ6HTMTA6e1ehoZxDKGkXqAM2o1TYgxNCX5d", - "E96CSRSUT1WUGKzDb2Dug3zWRgj6qKffNTUZUihjFc7g", - "E9hD3ikumJx1GVswDjnpCt6Uu4WG5mz1PDWCqdE5uhmo", - "ECd2JogmL8Qr4hox1zUNEn8aHFchE1tAh3JXM4UQBzzo", - "Ecs6YWKzgZXu3oS4WCyWzWf4kw2g7XnE7eWwq83TQBaG", - "ECULsxDc7pqadpQSQxFaNWAsemLW3wQq1vDKXg5P7GjW", - "EEN4pf92jyVoASZ6pQQMHcKXTF4d5T3cY1a942QhRasc", - "EEP7VNrtLt3tjM8DvqUVEsmwZxLKwHgEFWDtoMx2PQZB", - "Eik59s9go24w5KoyXGoyKSK1rUNYN2MLTv1iW2DFWkS3", - "EJ38tGihX9LtQ3q2eYGxUvLm6pzx8w6rXG2Q8BNhbeiM", - "EjcGVYigv2PA6MeZxRmgFot1P7eGQThFMS2Yh3cj5r2n", - "EKyzkF3pdGDR3Wnhuf3ouMoofnJi3r2XKioUuGqwrqB1", - "EqxCV4fz2unNzt8ydGrVyz24ngkH5n13x2wDSJ8DY6qi", - "EssmJHKwUffWWDBK4mb84QRQjWJEnuDui41T8ufcoqeZ", - "EUVBn58XXTX9RBTm1R7Wd8n8JkvBMQfc9uSn5wPhbdBL", - "Ev8D9dwYdfebkdLgAjwiJtCkqS882Uvrit5qN6NTeHMy", - "EVkRg5yjkmBP5tAmSiM9zBcrfnFE82rv3fdVvTLR2sxL", - "EwHxEEjLrrhzB2TUNMEJh8kNcDSnfBYvuZzDizBHF51J", - "EwUVzgSPe1zy2hfUGZxJAEP7Y1wheNgNsgratbzPELru", - "EXCMwETx5Txcvxt6YYqxFmhSpQKH5BVjdat3NE5eJJ6a", - "ExnG6VdMubFJfrB7qereo3YxUMyeZvTuZUVKfv7R1YZD", - "ExyEA6EegthLVNEjkj37FDGUnokPHqtEEe58ncBAww7u", - "EyhATWGrsfmfRZtUpCDiyW8vH7CfkT5gy15RtvNPmqby", - "EZUyrtZoBWMMoXTLzDo4RVTXi5XKYCs1kq7oESFLDvCP", - "F84kSGMUy81sHVF7HtZn8nPMRBau2ZC9uqGAZGJtHXYJ", - "f8e1k1Qz7zsv9gp1kVPnzBHCV8kDkfM8Rad3ZfHxFZN", - "Fa17nmHFt62kmerRQNGtgVWDxnuf7UD3PY2eeFfhpz2t", - "FAAvB4WnbSPNT35oUXDvkYj932KFRPi24dNBtrSpPvCY", - "FaGBP8LJrXE5h3cFRtPxz8x8695LQAYnvYn3NGtVtvrw", - "FAwRZwJgi7h81ZphYhLauZKvBHvkr3Dbhh6R8DsaD4Xv", - "FCQTtjeFK7Fj64aVDwdahfyxiG94uLnUjkmmXUq2esuf", - "FcWJ9zuq23C74KzeZtrSZMNXDnKFN9fQXwAyVDTZFpLr", - "FCWkGAHDWK41ANjiaoPudkCZRkvTecaEkoZQugezUnpr", - "Fd7btgySsrjuo25CJCj7oE7VPMyezDhnx7pZkj2v69Nk", - "FdmF6aFAy3pisaTwcQnvLf43z3pd1QnqrNzFMa2vKABA", - "FEpYb3oJbdPf77DPdQagkcmcJ4SqcfRDeCydKVkks4HK", - "FGiEdzde7Fco2WLpNQMat299hUVoykJdaA5hxdmCzHiS", - "fishfishrD9BwrQQiAcG6YeYZVUYVJf3tb9QGQPMJqF", - "FoigPJ6kL6Gth5Er6t9d1Nkh96Skadqw63Ciyjxc1f8H", - "forb5u56XgvzxiKfRt4FVNFQKJrd2LWAfNCsCqL6P7q", - "FPgkPgT5agEv7JY7czn1t5bKKewAkcBiPn1xQyiCcurc", - "FshmkeZbT8Q7NveSjVpy8FZBgJ6sigK8Etz1cX7Jmyu5", - "FtyZ7aQneFyJs6wKsMTt6m9JFjYEkHwZ2DhhtS6gw3Th", - "Fudp7uPDYNYQRxoq1Q4JiwJnzyxhVz37bGqRki3PBzS", - "FuSZq1Xkvkjkj16fGdhDtZb5ATtsZ8FH5a9KGsDhtZQP", - "FUyx2W6wDt7u363QgQRWQYuytE5uJWZLGJpuVh3RDiCa", - "FvBrooVoGfi56ux9L49HZLDHMt4iznYVDAMtyH2ee2LD", - "FVmo2S1GZBRJLS5GM2F5uYF6bcg4rM47dtkxHABKES1b", - "FVsjR8faKFZSisBatLNVo5bSH1jvHz3JvneVbyVTiV9K", - "FvTY9S6vutvfyP1eJG7RLiR1er6nk6cNTSP8q9WRpvWA", - "Fw3khiQmpKLSdNyoVR52WxbTWT9gjFSXFsZewknwLGb5", - "FxE69xVkPAUYh3Y2QCHJVWwVB8x1F3wbHnfKGoUvXn81", - "FZktwGYwu2JfbECgs4ELaXXJtz9oZyJEfiWa234is6By", - "G1X8Jrrfz3gfqZQo29jjwZ844XwjdPPEBaqNDWoAfEA", - "G2ccHPYPic368N1b6dHJBnE3tBmiceHGZefjk2FZuVfT", - "G2TBEh2ahNGS9tGnuBNyDduNjyfUtGhMcssgRb8b6KfH", - "G4BaMbWsp9uX7EX7dtv848xqfxtmoi6d44cNk4irEtvZ", - "G4dd6rLMW5aQEKFcYFHw148T8afjyavMyabsc86zACmq", - "G5rEbYLuVsTiXP1hUWkeJp9PptSujTGa3mFRqrxXgMx4", - "GAvEvUKfVkGjMgFhQjC6WAtzzM6YbHGvfC4PoCtrrfVz", - "GbpomwGXpPBfYpiMz6KWXBa23usJM6Cf426NQGzAKV2W", - "GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ", - "Gdo6FaCtTQqGYsmDQrX2icSZeqDCdVizGzBDNbiqCGbJ", - "Ge8M91yymAsZmjCyeAVCpxGA9k62CR8cxf4AhP1c38UP", - "GejR6mt9gxHtJ8Xe3cqamG7AL3Hx74w226o8p61QA5oG", - "GfCNi6GaCfEKyvpS8fs1D6VUdQcPJg4VrULvFFEBLFW6", - "GhuhvJcGcS4USKAt4JQsiYyZvcAj1MNzBhRiqR87wNv8", - "GinTsSooU4QChoqXFvEWnMLsM6iheLmLFFv681s9CeqY", - "GKu2xfGZopa8C9K11wduQWgP4W4H7EEcaNdsUb7mxhyr", - "GLh2T3KmWH4dUxGEVFuExffK4TLotmfeSCGg6fP7g78z", - "GLmkRrNqTSVi9ykTBQVX9M8cV9EwiCABknXVweS4QVxj", - "GmZ7xFQ4GHDbQw4CSnFT9pAHa15u35qTN8e259UrBh9D", - "GosJ8GHbSUunTQPY5xEyjhY2Eg5a9qSuPhNC4Ctztr7y", - "GRmtMtAeSL8HgX1p815ATQjaYU4Sk7XCP21i4yoFd3KS", - "GSXEn8TVBgiqfiLP5c8VmUrdAX8sWDZVE9M6p2kZFehG", - "GUFNuRw9JEAQwrJR71mRa2LbMRyrUfziYUzqY3KQwAXv", - "GUvRSvhhQRA1PhTpMaqW5hELHcPP9QP4W45tHFEbtqRi", - "GVjtyyy9HrgBmQ62TxjyUuaQDvuHNbnnrZgi9gqwpVYv", - "GWccEztr4AFmiMvvvXcib4feDZXCi6U13XrxponUHFWC", - "GwHH8ciFhR8vejWCqmg8FWZUCNtubPY2esALvy5tBvji", - "GwnQsVbbVsMhGqWV3gcVCF1364LRmftggyc5SmsYMLrY", - "Gyxhb2GGcB3s5h1HcHekRJYyAHRXEDP1FfX5fncE9edA", - "GYZdxwPwV3wTFVC8DdZuJQZDDRCg45AtqUai8cpSyAga", - "GZNnph4EvmyjjL5uzF9xNNTHyV46RzbkW4w4HYU8BQCW", - "H2oJUXwghyv6BwZH68jobU8jGutBji4v3WbPA96kc5Yd", - "H3WEH47bHUy9i9rmzdaxmoLagoUhbcJ2shPXcsp8QdJC", - "H5FD5GxuE46hqi5paMkcqt9WeHvszZA7RgBfMoMpfNDK", - "H7tpxumDErX9DXNTKKBFTDmynXBF32QQ8n3QjiQfLn2i", - "HahmUFR44BXFP7fVLsnd4pyaE7GoN1KKV1hdL2eVUpok", - "heoSbe83UDZA5LNR6F33QHVk9iZXpxPKcNRtVpDczXL", - "Hj2jzpAp57KyM3SmnYwJbDVrQ8tTWizMon2hhzYzwxet", - "Hmube7PkFmvattfygQgEyWe4GfZ9Dskj4Zc9YFfRj9JU", - "HoXANZnWTGeePertqWkMEnnhgXjTjzpfWaT2kja2ZgVU", - "Hp9NMFfFhDQJCkgUHLajoWqTjm1xxdvQEyUnoYn1GWFX", - "HPca8Y8aMnkrTi87MJFHDvMtJVkvyMxFvkuLsoFEoELy", - "HPdVgk7NhewBTKDCyqKYFXLu3pErnUo5W9KLSLd18JJv", - "HPN8ANgpeF5mcViFW6fTCXGWPdQ6LhRWvcx86JVEkFC2", - "HQATLHBJcU7DET6b6NWNMpfsZVZ1PRnbfkCtcFCT5reo", - "Hqc2qT3vXvBSKozmz7Rd7gLF6jUJHuQEGBTnCHzEBnqk", - "HS8DF8wP3A8qSHPnzbE6pSvXub4FeZQ6xMNSJuqArAHS", - "Hsb14Gkhjbp6FinDcPRwrThS8BYsTnrhGY8Ui4f3EY7V", - "HsGWhcLqVsue45i4vMxku3YEVGF5cYxUSTaa6gwieSGN", - "HtzxUabNfYNJR43FUmcpkgmtANZahbq5iASB5oiboXzF", - "HU8uKcH8b2GRD5T2LYKDzV82H7CiRLTQLwYTNxAD7b62", - "HVWzcQZ12pvZN726XXgA2jBfDuj6wDFwSFVdzxooi7qx", - "HW4zorvt6xDwhU36RqjcWNwU8YMj9tiqnAafBKW4cqV", - "HW7ntfUHapD5o7McDuPfGvkfzrPcmuPSbZMMoe2gksKQ", - "HwdfNWCqP2vXRvaHqQhoVUM2uPndaY8DDJzzBxCoPNHU", - "HzrEstnLfzsijhaD6z5frkSE2vWZEH5EUfn3bU9swo1f", - "HzvGtvXFzMeJwNYcUu5pw8yyRxF2tLEvDSSFsAEBcBK2", - "HZzEML2w5Qs6cccMd7o57Vx2sQUuuTaiecEcMU2xceSK", - "J2jV3gQsvX2htBXHeNStAVvMJaPe3RgNotwfav9pyS6y", - "J5MroSHMzcPUTXcnpXygeCFnXJ39NBG5RRQRYD29ZwNy", - "J711fLahrgkEnPaCrbGUCpGemmeVg2LsaZhmC6HNPbXk", - "J78SNwDW6G86sMmh7djnBKGjewXNpjD74sJTjJ1iNgTH", - "J7jT9mGjhfXdGFdp9XT97Sd8ynFMe5e2L8DqXJQr8qgs", - "JCmdhNCyzypryaQUGLGxbCM366dScTD4tVy5ooSWyaBZ", - "JCZNdppKyur55JqY5VBctkVjxEcgoQq3RmBuVbQxSCEq", - "JD6R8sK3cu7tphNMyhzxSGnSf9DcFUacXBgqycvGAjai", - "JdJWLp5edqUHQB7K9mA3L1gFbFcrS8aeaar6hQ6M2Su", - "JDScHrbfa4DEmqA4j5JTVc3wtwqXXeDCrjntRo2pWoLP", - "JokerEfTSznB2aTmowy4QPqjyajLMuYM6Jd4TDnKPNc", - "LunaowJnt875WWoqDkhHhE93SNYHa6tfFNVn1rqc57c", - "MCFmmmXdzTKjBEoMggi8JGFJmd856uYSowuH2sCU5kx", - "N55CrumveNQrXFn9oL4xkFDB9K8q5PxwrYaAomrxemz", - "narPxmKTwkUxvcXhueccHT8xbE8og2Vb7NrLBm8kcrh", - "nSGZ3tv2UhskkPqiB666yDVj7PTi9qKgDqvjHyw5JgM", - "nVmiYamBpwzEqxykaGBWvY9W4R7rmK1JudonPRhmkAw", - "Pidptxt5SEqgeK9HgqacrY2KEEnMqtUFSmAucLwnTPG", - "PR3GtaLUjL8rSGcAQtV9NYGTWhpys5kYRDUSCMF5N4j", - "pZ2nxiW1M78Ez9Tk5DcQyw1nWpmPFVZk8KDGKWbvvUV", - "RBFiUqjYuy4mupzZaU96ctXJBy23sRBRsL3KivDAsFM", - "rusx3KV69WGvsEbWa2HxjXp9GfHpjojM94BqsnfxKhx", - "SFundNVpuWk89g211WKUZGkuu4BsKSp7PbnmRsPZLos", - "siriXy5CcarNiz4XL8ssBQGiy2PwReVLny3Bcxq6Ymb", - "SoLiDDAQBEK1LK8apZcZqY7FunqeqDY6nYXMabQZvPB", - "spcti6GQVvinbtHU9UAkbXhjTcBJaba1NVx4tmK4M5F", - "uEhHSnCXvWgtgvVaYscPHjG13G3peMmngQQ2ghC54i3", - "WJguyKr593U9gDSdUu9Rcr1TMKo6pTse9LFZfCArR5K", - "wpd8e4dzFVnCQY3jPuB9J7pKYQd6Mstz5tjWzF97Kxb", - "Zb8KTJXwFvBTnbEDbyxWs8AVWjjipbXNFAfc1Jsbhey", - "zeroT6PTAEjipvZuACTh1mbGCqTHgA6i1ped9DcuidX", - ] -); diff --git a/stake-o-matic/src/validators_app.rs b/stake-o-matic/src/validators_app.rs deleted file mode 100644 index 4d8a9b588c..0000000000 --- a/stake-o-matic/src/validators_app.rs +++ /dev/null @@ -1,196 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; - -#[allow(dead_code)] -#[derive(Debug)] -pub enum ClusterJson { - MainnetBeta, - Testnet, -} - -impl Default for ClusterJson { - fn default() -> Self { - Self::MainnetBeta - } -} - -impl AsRef for ClusterJson { - fn as_ref(&self) -> &str { - match self { - Self::MainnetBeta => "mainnet.json", - Self::Testnet => "testnet.json", - } - } -} - -const DEFAULT_BASE_URL: &str = "https://www.validators.app/api/v1/"; -const TOKEN_HTTP_HEADER_NAME: &str = "Token"; - -#[derive(Debug)] -pub struct ClientConfig { - pub base_url: String, - pub cluster: ClusterJson, - pub api_token: String, -} - -impl Default for ClientConfig { - fn default() -> Self { - Self { - base_url: DEFAULT_BASE_URL.to_string(), - cluster: ClusterJson::default(), - api_token: String::default(), - } - } -} - -#[derive(Debug)] -enum Endpoint { - Ping, - Validators, -} - -impl Endpoint { - fn with_cluster(path: &str, cluster: &ClusterJson) -> String { - format!("{}/{}", path, cluster.as_ref()) - } - pub fn path(&self, cluster: &ClusterJson) -> String { - match self { - Self::Ping => "ping.json".to_string(), - Self::Validators => Self::with_cluster("validators", cluster), - } - } -} - -#[derive(Debug, Deserialize, Serialize)] -struct PingResponse { - answer: String, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct ValidatorsResponseEntry { - pub account: Option, - pub active_stake: Option, - pub commission: Option, - pub created_at: Option, - pub data_center_concentration_score: Option, - pub data_center_host: Option, - pub data_center_key: Option, - pub delinquent: Option, - pub details: Option, - pub keybase_id: Option, - pub name: Option, - pub network: Option, - pub ping_time: Option, - pub published_information_score: Option, - pub root_distance_score: Option, - pub security_report_score: Option, - pub skipped_slot_percent: Option, - pub skipped_slot_score: Option, - pub skipped_slots: Option, - pub software_version: Option, - pub software_version_score: Option, - pub stake_concentration_score: Option, - pub total_score: Option, - pub updated_at: Option, - pub url: Option, - pub vote_account: Option, - pub vote_distance_score: Option, - pub www_url: Option, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct ValidatorsResponse(Vec); - -impl AsRef> for ValidatorsResponse { - fn as_ref(&self) -> &Vec { - &self.0 - } -} - -#[allow(dead_code)] -#[derive(Debug, Clone, Copy)] -pub enum SortKind { - Score, - Name, - Stake, -} - -impl std::fmt::Display for SortKind { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Self::Score => write!(f, "score"), - Self::Name => write!(f, "name"), - Self::Stake => write!(f, "stake"), - } - } -} - -pub type Limit = u32; - -pub struct Client { - base_url: reqwest::Url, - cluster: ClusterJson, - api_token: String, - client: reqwest::blocking::Client, -} - -impl Client { - pub fn new>(api_token: T) -> Self { - let config = ClientConfig { - api_token: api_token.as_ref().to_string(), - ..ClientConfig::default() - }; - Self::new_with_config(config) - } - - pub fn new_with_config(config: ClientConfig) -> Self { - let ClientConfig { - base_url, - cluster, - api_token, - } = config; - Self { - base_url: reqwest::Url::parse(&base_url).unwrap(), - cluster, - api_token, - client: reqwest::blocking::Client::new(), - } - } - - fn request( - &self, - endpoint: Endpoint, - query: &HashMap, - ) -> reqwest::Result { - let url = self.base_url.join(&endpoint.path(&self.cluster)).unwrap(); - let request = self - .client - .get(url) - .header(TOKEN_HTTP_HEADER_NAME, &self.api_token) - .query(&query) - .build()?; - self.client.execute(request) - } - - #[allow(dead_code)] - pub fn ping(&self) -> reqwest::Result<()> { - let response = self.request(Endpoint::Ping, &HashMap::new())?; - response.json::().map(|_| ()) - } - - pub fn validators( - &self, - sort: Option, - limit: Option, - ) -> reqwest::Result { - let mut query = HashMap::new(); - if let Some(sort) = sort { - query.insert("sort".into(), sort.to_string()); - } - if let Some(limit) = limit { - query.insert("limit".into(), limit.to_string()); - } - let response = self.request(Endpoint::Validators, &query)?; - response.json::() - } -} diff --git a/stake-o-matic/stake-o-matic.sh b/stake-o-matic/stake-o-matic.sh deleted file mode 100755 index 1701389937..0000000000 --- a/stake-o-matic/stake-o-matic.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -# -# Downloads and runs the latest stake-o-matic binary -# -set -e - -solana_version=edge -curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v1.0.0/install/solana-install-init.sh \ - | sh -s - $solana_version \ - --no-modify-path \ - --data-dir ./solana-install \ - --config ./solana-install/config.yml - -PATH="$(realpath "$PWD"/solana-install/releases/"$solana_version"*/solana-release/bin/):$PATH" -echo PATH="$PATH" - -set -x -solana --version -exec solana-stake-o-matic "$@"